LLVM学习笔记(14)补2

3.3.6.4.5. 定义获取权重及压力数据方法

目标机器需要提供以下方法来让CodeGen获取权重以及压力数据:

getRegPressureLimit(),getRegClassWeight(),getRegUnitWeight(),getNumRegPressureSets(),getRegPressureSetName(),getRegPressureSetLimit(),getRegClassPressureSets(),getRegUnitPressureSets()。

首先被输出的getRegClassWeight()方法的定义。它返回以所属寄存器单元(RegUnit)权重来衡量的寄存器类权重。

RegisterInfoEmitter::runTargetDesc(续)

1373    EmitRegUnitPressure(OS, RegBank, ClassName);

1374 

1375    // Emit the constructor of the class...

1376    OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n";

1377    OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n";

1378    OS << "extern const unsigned " << TargetName << "LaneMaskLists[];\n";

1379    OS << "extern const char " << TargetName << "RegStrings[];\n";

1380    OS << "extern const char " << TargetName << "RegClassStrings[];\n";

1381    OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2];\n";

1382    OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n";

1383    OS << "extern const MCRegisterInfo::SubRegCoveredBits "

1384       << TargetName << "SubRegIdxRanges[];\n";

1385    OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n";

RegisterInfoEmitter::EmitRegUnitPressure()的176行,CodeGenRegBank::getNumRegPressureSets()方法返回容器RegUnitSets的大小。RegUnitSets容器里记录了与寄存器类相关的RegUnit同类集,这个同类集的权重,以及这些同类集间的顺序号。

172     void RegisterInfoEmitter::

173     EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank,

174                         const std::string &ClassName) {

175       unsigned NumRCs = RegBank.getRegClasses().size();

176       unsigned NumSets = RegBank.getNumRegPressureSets();

177    

178       OS << "/// Get the weight in units of pressure for this register class.\n"

179          << "const RegClassWeight &" << ClassName << "::\n"

180          << "getRegClassWeight(const TargetRegisterClass *RC) const {\n"

181          << "  static const RegClassWeight RCWeightTable[] = {\n";

182       for (const auto &RC : RegBank.getRegClasses()) {

183         const CodeGenRegister::Vec &Regs = RC.getMembers();

184         if (Regs.empty())

185           OS << "    {0, 0";

186         else {

187           std::vector<unsigned> RegUnits;

188           RC.buildRegUnitSet(RegUnits);

189         OS << "    {" << (*Regs.begin())->getWeight(RegBank)

190              << ", " << RegBank.getRegUnitSetWeight(RegUnits);

191         }

192         OS << "},  \t// " << RC.getName() << "\n";

193       }

194       OS << "  };\n"

195          << "  return RCWeightTable[RC->getID()];\n"

196          << "}\n\n";

182行循环通过CodeGenRegisterClass::buildRegUnitSet()方法计算一个寄存器类的RegUnit同类集,189行通过getWeight()方法得到该寄存器类中第一个寄存器的权重,190行的getRegUnitSetWeight()方法则计算RegUnit同类集的权重。那么以X86目标机器为例,我们将输出这个方法:

const RegClassWeight &X86GenRegisterInfo::

getRegClassWeight(const TargetRegisterClass *RC) const {

  static const RegClassWeight RCWeightTable[] = {

    {1, 20},    // GR8

    {1, 8},      // GR8_NOREX

    {1, 8},      // VK1

    {1, 8},      // VK2

    {1, 8},      // VK4

    {1, 8},      // VK8

    {1, 7},      // VK1WM

    {1, 7},      // VK2WM

    {1, 7},      // VK4WM

    {1, 7},      // VK8WM

    {1, 4},      // GR8_ABCD_H

    {1, 4},      // GR8_ABCD_L

    {2, 32},    // GR16

    {2, 16},    // GR16_NOREX

    {1, 8},      // VK16

    {1, 7},      // VK16WM

    {1, 6},      // SEGMENT_REG

    {2, 8},      // GR16_ABCD

    {0, 0},      // FPCCR

    {1, 32},    // FR32X

    {1, 16},    // FR32

    {2, 32},    // GR32

    {2, 30},    // GR32_NOAX

    {2, 30},    // GR32_NOSP

    {2, 28},    // GR32_NOAX_and_GR32_NOSP

    {1, 8},      // DEBUG_REG

    {2, 16},    // GR32_NOREX

    {1, 8},      // VK32

    {2, 14},    // GR32_NOAX_and_GR32_NOREX

    {2, 14},    // GR32_NOREX_NOSP

    {1, 7},      // RFP32

    {1, 7},      // VK32WM

    {2, 12},    // GR32_NOAX_and_GR32_NOREX_NOSP

    {2, 8},      // GR32_ABCD

    {2, 6},      // GR32_ABCD_and_GR32_NOAX

    {2, 6},      // GR32_TC

    {2, 4},      // GR32_AD

    {2, 4},      // GR32_NOAX_and_GR32_TC

    {0, 0},      // CCR

    {2, 2},      // GR32_AD_and_GR32_NOAX

    {1, 7},      // RFP64

    {1, 32},    // FR64X

    {2, 34},    // GR64

    {1, 16},    // CONTROL_REG

    {1, 16},    // FR64

    {2, 32},    // GR64_with_sub_8bit

    {2, 30},    // GR64_NOSP

    {2, 30},    // GR64_with_sub_32bit_in_GR32_NOAX

    {2, 28},    // GR64_with_sub_32bit_in_GR32_NOAX_and_GR32_NOSP

    {2, 18},    // GR64_NOREX

    {2, 18},    // GR64_TC

    {2, 16},    // GR64_NOSP_and_GR64_TC

    {2, 16},    // GR64_with_sub_16bit_in_GR16_NOREX

    {1, 8},      // VK64

    {1, 8},      // VR64

    {2, 14},    // GR64_NOREX_NOSP

    {2, 14},    // GR64_TC_and_GR64_with_sub_32bit_in_GR32_NOAX

    {2, 14},    // GR64_with_sub_32bit_in_GR32_NOAX_and_GR32_NOREX

    {1, 7},      // VK64WM

    {2, 12},    // GR64_NOREX_and_GR64_TC

    {2, 12},    // GR64_TCW64

    {2, 12},    // GR64_with_sub_32bit_in_GR32_NOAX_and_GR32_NOREX_NOSP

    {2, 10},    // GR64_NOREX_NOSP_and_GR64_TC

    {2, 10},    // GR64_TCW64_and_GR64_with_sub_32bit_in_GR32_NOAX

    {2, 8},      // GR64_ABCD

    {2, 8},      // GR64_TC_and_GR64_with_sub_32bit_in_GR32_NOAX_and_GR32_NOREX

    {2, 6},      // GR64_with_sub_32bit_in_GR32_ABCD_and_GR32_NOAX

    {2, 6},      // GR64_with_sub_32bit_in_GR32_TC

    {2, 4},      // GR64_with_sub_32bit_in_GR32_AD

    {2, 4},      // GR64_with_sub_32bit_in_GR32_NOAX_and_GR32_TC

    {2, 2},      // GR64_with_sub_32bit_in_GR32_AD_and_GR32_NOAX

    {0, 0},      // RST

    {1, 7},      // RFP80

    {1, 32},    // VR128X

    {1, 16},    // VR128

    {1, 4},      // BNDR

    {1, 32},    // VR256X

    {1, 16},    // VR256

    {1, 32},    // VR512

    {1, 16},    // VR512_with_sub_xmm_in_FR32

  };

  return RCWeightTable[RC->getID()];

}

数组RCWeightTable的每一项对应一个寄存器类,而每一项里第一个数字是该类中第一个寄存器的权重,第二个数字则是该类寄存器RegUnit同类集的权重,也称为该寄存器类的权重上限。

接下来输出获取寄存器单元权重的方法getRegUnitWeight()。

RegisterInfoEmitter::EmitRegUnitPressure(续)

198       // Reasonable targets (not ARMv7) have unit weight for all units, so don't

199       // bother generating a table.

200       bool RegUnitsHaveUnitWeight = true;

201       for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();

202            UnitIdx < UnitEnd; ++UnitIdx) {

203         if (RegBank.getRegUnit(UnitIdx).Weight > 1)

204           RegUnitsHaveUnitWeight = false;

205       }

206       OS << "/// Get the weight in units of pressure for this register unit.\n"

207          << "unsigned " << ClassName << "::\n"

208          << "getRegUnitWeight(unsigned RegUnit) const {\n"

209          << "  assert(RegUnit < " << RegBank.getNumNativeRegUnits()

210          << " && \"invalid register unit\");\n";

211       if (!RegUnitsHaveUnitWeight) {

212         OS << "  static const uint8_t RUWeightTable[] = {\n    ";

213         for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();

214              UnitIdx < UnitEnd; ++UnitIdx) {

215           const RegUnit &RU = RegBank.getRegUnit(UnitIdx);

216           assert(RU.Weight < 256 && "RegUnit too heavy");

217           OS << RU.Weight << ", ";

218         }

219         OS << "};\n"

220            << "  return RUWeightTable[RegUnit];\n";

221       }

222       else {

223         OS << "  // All register units have unit weight.\n"

224            << "  return 1;\n";

225       }

226       OS << "}\n\n";

227

228       OS << "\n"

229          << "// Get the number of dimensions of register pressure.\n"

230          << "unsigned " << ClassName << "::getNumRegPressureSets() const {\n"

231          << "  return " << NumSets << ";\n}\n\n";

230

233       OS << "// Get the name of this register unit pressure set.\n"

234          << "const char *" << ClassName << "::\n"

235          << "getRegPressureSetName(unsigned Idx) const {\n"

236          << "  static const char *const PressureNameTable[] = {\n";

237       unsigned MaxRegUnitWeight = 0;

238       for (unsigned i = 0; i < NumSets; ++i ) {

239         const RegUnitSet &RegUnits = RegBank.getRegSetAt(i);

240         MaxRegUnitWeight = std::max(MaxRegUnitWeight, RegUnits.Weight);

241         OS << "    \"" << RegUnits.Name << "\",\n";

242       }

243       OS << "    nullptr };\n"

244          << "  return PressureNameTable[Idx];\n"

245          << "}\n\n";

246    

247       OS << "// Get the register unit pressure limit for this dimension.\n"

248          << "// This limit must be adjusted dynamically for reserved registers.\n"

249          << "unsigned " << ClassName << "::\n"

250          << "getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const {\n"

251          << "  static const " << getMinimalTypeForRange(MaxRegUnitWeight)

252          << " PressureLimitTable[] = {\n";

253       for (unsigned i = 0; i < NumSets; ++i ) {

254         const RegUnitSet &RegUnits = RegBank.getRegSetAt(i);

255         OS << "    " << RegUnits.Weight << ",  \t// " << i << ": "

256            << RegUnits.Name << "\n";

257       }

258       OS << "  };\n"

259          << "  return PressureLimitTable[Idx];\n"

260          << "}\n\n";

前面看到Native单元,如果没有特殊情况,其Weight就是1,它是寄存器真正可用的部分(相比为调整权重加入的单元)。201行循环遍历所有的Native单元,确定是否存在权重大于1的单元。如果没有,就可以直接返回1,否则需要声明一个RUWeightTable数组来给出相应的权重。对于X86目标机器,输出的方法是这样的。

unsigned X86GenRegisterInfo::

getRegUnitWeight(unsigned RegUnit) const {

  assert(RegUnit < 131 && "invalid register unit");

  // All register units have unit weight.

  return 1;

}

接下来输出返回寄存器压力描述维度数(即RegUnit的同类集)的方法getNumRegPressureSets()。X86目标机器的是:

unsigned X86GenRegisterInfo::getNumRegPressureSets() const {

  return 22;            <-- v7.0这个值是30

}

以及返回寄存器压力描述维度数名字的方法getRegPressureSetName()。RegUnit的同类集的名字在构建时已经设置好。

const char *X86GenRegisterInfo::

getRegPressureSetName(unsigned Idx) const {

  static const char *const PressureNameTable[] = {

    "GR8_ABCD_H",

    "GR8_ABCD_L",

    "BNDR",

    "SEGMENT_REG",

    "RFP32",

    "GR8_NOREX",

    "VK1",

    "DEBUG_REG",

    "VR64",

    "GR8_NOREX+GR64_NOREX_and_GR64_TC",

    "GR8_NOREX+GR64_TCW64",

    "FR32",

    "CONTROL_REG",

    "GR64_NOREX",

    "GR8",

    "GR8_NOREX+GR64_TC",

    "GR8+GR64_TCW64",

    "GR64_NOREX+GR64_TC",

    "GR8+GR64_NOREX",

    "GR8+GR64_TC",

    "FR32X",

    "GR64",

    nullptr };

  return PressureNameTable[Idx];

}

接下来输出获取出寄存器压力指定维度数据(即指定RegUnit同类集,这些同类集参见上面getRegPressureSetName()定义的名字)的getRegPressureSetLimit()方法。

unsigned X86GenRegisterInfo::

getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const {

  static const uint8_t PressureLimitTable[] = {

    4,     // 0: GR8_ABCD_H

    4,     // 1: GR8_ABCD_L

    4,     // 2: BNDR

    6,     // 3: SEGMENT_REG

    7,     // 4: RFP32

    8,     // 5: GR8_NOREX

    8,     // 6: VK1

    8,     // 7: DEBUG_REG

    8,     // 8: VR64

    14,  // 9: GR8_NOREX+GR64_NOREX_and_GR64_TC

    14,  // 10: GR8_NOREX+GR64_TCW64

    16,  // 11: FR32

    16,  // 12: CONTROL_REG

    18,  // 13: GR64_NOREX

    20,  // 14: GR8

    20,  // 15: GR8_NOREX+GR64_TC

    23,  // 16: GR8+GR64_TCW64

    24,   // 17: GR64_NOREX+GR64_TC

    26,  // 18: GR8+GR64_NOREX

    27,  // 19: GR8+GR64_TC

    32,  // 20: FR32X

    34,  // 21: GR64

  };

  return PressureLimitTable[Idx];

}

给出的实际上是指定RegUnit同类集的权重。

接着,266行的getNumRegClassPressureSetLists()方法返回CodeGenRegBank的RegClassUnitSets容器的大小,这个容器记录了每个寄存器类RegUnit同类集超集的RegUnit同类集的集合。

RegisterInfoEmitter::EmitRegUnitPressure(续)

262       SequenceToOffsetTable<std::vector<int>> PSetsSeqs;

263    

264       // This table may be larger than NumRCs if some register units needed a list

265       // of unit sets that did not correspond to a register class.

266       unsigned NumRCUnitSets = RegBank.getNumRegClassPressureSetLists();

267       std::vector<std::vector<int>> PSets(NumRCUnitSets);

268    

269       for (unsigned i = 0, e = NumRCUnitSets; i != e; ++i) {

270         ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i);

271         PSets[i].reserve(PSetIDs.size());

272        for (ArrayRef<unsigned>::iterator PSetI = PSetIDs.begin(),

273                PSetE = PSetIDs.end(); PSetI != PSetE; ++PSetI) {

274           PSets[i].push_back(RegBank.getRegPressureSet(*PSetI).Order);

275         }

276         std::sort(PSets[i].begin(), PSets[i].end());

277         PSetsSeqs.add(PSets[i]);

278       }

279    

280       PSetsSeqs.layout();

281    

282       OS << "/// Table of pressure sets per register class or unit.\n"

283          << "static const int RCSetsTable[] = {\n";

284       PSetsSeqs.emit(OS, printInt, "-1");

285       OS << "};\n\n";

286    

287       OS << "/// Get the dimensions of register pressure impacted by this "

288          << "register class.\n"

289          << "/// Returns a -1 terminated array of pressure set IDs\n"

290          << "const int* " << ClassName << "::\n"

291         << "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n";

292       OS << "  static const " << getMinimalTypeForRange(PSetsSeqs.size()-1)

293          << " RCSetStartTable[] = {\n    ";

294       for (unsigned i = 0, e = NumRCs; i != e; ++i) {

295         OS << PSetsSeqs.get(PSets[i]) << ",";

296       }

297       OS << "};\n"

298          << "  return &RCSetsTable[RCSetStartTable[RC->getID()]];\n"

299          << "}\n\n";

300    

301       OS << "/// Get the dimensions of register pressure impacted by this "

302          << "register unit.\n"

303          << "/// Returns a -1 terminated array of pressure set IDs\n"

304          << "const int* " << ClassName << "::\n"

305          << "getRegUnitPressureSets(unsigned RegUnit) const {\n"

306          << "  assert(RegUnit < " << RegBank.getNumNativeRegUnits()

307          << " && \"invalid register unit\");\n";

308       OS << "  static const " << getMinimalTypeForRange(PSetsSeqs.size()-1)

309          << " RUSetStartTable[] = {\n    ";

310       for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits();

311            UnitIdx < UnitEnd; ++UnitIdx) {

312         OS << PSetsSeqs.get(PSets[RegBank.getRegUnit(UnitIdx).RegClassUnitSetsIdx])

313            << ",";

314       }

315       OS << "};\n"

316          << "  return &RCSetsTable[RUSetStartTable[RegUnit]];\n"

317          << "}\n\n";

318     }

269行循环将CodeGenRegBank的RegClassUnitSets容器的内容进行差分编码。差分编码的内容是RegUnitSet实例的Order域(表示这些对象以集合大小排序的优先级)如果结合RegUnitSetOrder与RegUnitSets容器,可以得到这些RegUnitSet对象。在284行输出这个差分表。

static const int RCSetsTable[] = {

  /* 0 */ 2, -1,

  /* 2 */ 3, -1,

  /* 4 */ 4, -1,

  /* 6 */ 6, -1,

  /* 8 */ 7, -1,

  /* 10 */ 8, -1,

  /* 12 */ 12, -1,

  /* 14 */ 11, 20, -1,

  /* 17 */ 13, 17, 18, 21, -1,

  /* 22 */ 15, 17, 19, 21, -1,

  /* 27 */ 10, 15, 16, 17, 19, 21, -1,

  /* 34 */ 14, 16, 18, 19, 21, -1,

  /* 40 */ 9, 13, 15, 17, 18, 19, 21, -1,

  /* 48 */ 13, 14, 16, 17, 18, 19, 21, -1,

  /* 56 */ 10, 14, 15, 16, 17, 18, 19, 21, -1,

  /* 65 */ 9, 13, 14, 15, 16, 17, 18, 19, 21, -1,

  /* 75 */ 0, 5, 9, 10, 13, 14, 15, 16, 17, 18, 19, 21, -1,

  /* 88 */ 1, 5, 9, 10, 13, 14, 15, 16, 17, 18, 19, 21, -1,

};

注意,这个差分表以-1为终结符。

因为这个差分表的内容是CodeGenRegBank的RegClassUnitSets容器的内容,因此给定一个寄存器类,我们可以知道所有作为其超集的RegUnit同类集。

293~296行输出的方法getRegClassPressureSets()返回这些同类集ID的地址。

const int* X86GenRegisterInfo::

getRegClassPressureSets(const TargetRegisterClass *RC) const {

  static const uint8_t RCSetStartTable[] = {34,76,6,6,6,6,6,6,6,6,75,88,20,17,6,6,2,76,1,15,14,20,20,20,20,8,17,6,17,17,4,6,17,76,76,76,76,76,1,76,4,15,20,12,14,20,20,20,20,17,22,22,17,6,10,17,22,17,6,40,27,17,40,27,76,40,76,76,76,76,76,1,4,15,14,0,15,14,15,14,};

  return &RCSetsTable[RCSetStartTable[RC->getID()]];

}

其中,数组RCSetStartTable给出在RCSetsTable中的偏移。

另一个类似的方法getRegUnitPressureSets()返回包含一个指定RegUnit的RegUnit同类集的集合。

const int* X86GenRegisterInfo::

getRegUnitPressureSets(unsigned RegUnit) const {

  assert(RegUnit < 131 && "invalid register unit");

  static const uint8_t RUSetStartTable[] = {75,88,75,88,48,75,88,2,75,65,88,2,1,40,1,2,65,48,1,2,2,1,2,0,0,0,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,8,8,8,8,8,8,8,8,1,1,1,1,1,1,1,1,4,4,4,4,4,4,4,1,6,6,6,6,6,6,6,6,10,10,10,10,10,10,10,10,56,56,34,56,34,34,34,34,1,1,1,1,1,1,1,1,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,};

  return &RCSetsTable[RUSetStartTable[RegUnit]];

}

接下来声明了这样一组下面要用到的数组。

extern const MCRegisterDesc X86RegDesc[];

extern const MCPhysReg X86RegDiffLists[];

extern const unsigned X86LaneMaskLists[];

extern const char X86RegStrings[];

extern const char X86RegClassStrings[];

extern const MCPhysReg X86RegUnitRoots[][2];

extern const uint16_t X86SubRegIdxLists[];

extern const MCRegisterInfo::SubRegCoveredBits X86SubRegIdxRanges[];

extern const uint16_t X86RegEncodingTable[];

猜你喜欢

转载自blog.csdn.net/wuhui_gdnt/article/details/88737186