| 1 | //===- MatchTable.cpp -----------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "MatchTable.h" |
| 10 | #include "llvm/ADT/Twine.h" |
| 11 | #include "llvm/Support/LEB128.h" |
| 12 | #include "llvm/Support/ScopedPrinter.h" |
| 13 | #include "llvm/Support/raw_ostream.h" |
| 14 | #include "llvm/TableGen/Record.h" |
| 15 | |
| 16 | #define DEBUG_TYPE "gi-match-table" |
| 17 | |
| 18 | namespace llvm { |
| 19 | namespace gi { |
| 20 | // GIMT_Encode2/4/8 |
| 21 | constexpr StringLiteral EncodeMacroName = "GIMT_Encode" ; |
| 22 | |
| 23 | //===- Helpers ------------------------------------------------------------===// |
| 24 | |
| 25 | void emitEncodingMacrosDef(raw_ostream &OS) { |
| 26 | OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n" |
| 27 | << "#define " << EncodeMacroName << "2(Val)" |
| 28 | << " uint8_t(Val), uint8_t((Val) >> 8)\n" |
| 29 | << "#define " << EncodeMacroName << "4(Val)" |
| 30 | << " uint8_t(Val), uint8_t((Val) >> 8), " |
| 31 | "uint8_t((Val) >> 16), uint8_t((Val) >> 24)\n" |
| 32 | << "#define " << EncodeMacroName << "8(Val)" |
| 33 | << " uint8_t(Val), uint8_t((Val) >> 8), " |
| 34 | "uint8_t((Val) >> 16), uint8_t((Val) >> 24), " |
| 35 | "uint8_t(uint64_t(Val) >> 32), uint8_t(uint64_t(Val) >> 40), " |
| 36 | "uint8_t(uint64_t(Val) >> 48), uint8_t(uint64_t(Val) >> 56)\n" |
| 37 | << "#else\n" |
| 38 | << "#define " << EncodeMacroName << "2(Val)" |
| 39 | << " uint8_t((Val) >> 8), uint8_t(Val)\n" |
| 40 | << "#define " << EncodeMacroName << "4(Val)" |
| 41 | << " uint8_t((Val) >> 24), uint8_t((Val) >> 16), " |
| 42 | "uint8_t((Val) >> 8), uint8_t(Val)\n" |
| 43 | << "#define " << EncodeMacroName << "8(Val)" |
| 44 | << " uint8_t(uint64_t(Val) >> 56), uint8_t(uint64_t(Val) >> 48), " |
| 45 | "uint8_t(uint64_t(Val) >> 40), uint8_t(uint64_t(Val) >> 32), " |
| 46 | "uint8_t((Val) >> 24), uint8_t((Val) >> 16), " |
| 47 | "uint8_t((Val) >> 8), uint8_t(Val)\n" |
| 48 | << "#endif\n" ; |
| 49 | } |
| 50 | |
| 51 | void emitEncodingMacrosUndef(raw_ostream &OS) { |
| 52 | OS << "#undef " << EncodeMacroName << "2\n" |
| 53 | << "#undef " << EncodeMacroName << "4\n" |
| 54 | << "#undef " << EncodeMacroName << "8\n" ; |
| 55 | } |
| 56 | |
| 57 | std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset, |
| 58 | int HwModeIdx) { |
| 59 | std::string Name = "GIFBS" ; |
| 60 | for (const Record *Feature : FeatureBitset) |
| 61 | Name += ("_" + Feature->getName()).str(); |
| 62 | if (HwModeIdx >= 0) |
| 63 | Name += ("_HwMode" + std::to_string(val: HwModeIdx)); |
| 64 | return Name; |
| 65 | } |
| 66 | |
| 67 | static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) { |
| 68 | if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8) |
| 69 | return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")" ).str(); |
| 70 | llvm_unreachable("Unsupported number of bytes!" ); |
| 71 | } |
| 72 | |
| 73 | //===- MatchTableRecord ---------------------------------------------------===// |
| 74 | |
| 75 | void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis, |
| 76 | const MatchTable &Table) const { |
| 77 | bool = |
| 78 | LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows); |
| 79 | if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows)) |
| 80 | UseLineComment = false; |
| 81 | |
| 82 | if (Flags & MTRF_Comment) |
| 83 | OS << (UseLineComment ? "// " : "/*" ); |
| 84 | |
| 85 | if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment))) |
| 86 | OS << getEncodedEmitStr(NamedValue: EmitStr, NumBytes: NumElements); |
| 87 | else |
| 88 | OS << EmitStr; |
| 89 | |
| 90 | if (Flags & MTRF_Label) |
| 91 | OS << ": @" << Table.getLabelIndex(LabelID); |
| 92 | |
| 93 | if ((Flags & MTRF_Comment) && !UseLineComment) |
| 94 | OS << "*/" ; |
| 95 | |
| 96 | if (Flags & MTRF_JumpTarget) { |
| 97 | if (Flags & MTRF_Comment) |
| 98 | OS << " " ; |
| 99 | // TODO: Could encode this AOT to speed up build of generated file |
| 100 | OS << getEncodedEmitStr(NamedValue: llvm::to_string(Value: Table.getLabelIndex(LabelID)), |
| 101 | NumBytes: NumElements); |
| 102 | } |
| 103 | |
| 104 | if (Flags & MTRF_CommaFollows) { |
| 105 | OS << "," ; |
| 106 | if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows)) |
| 107 | OS << " " ; |
| 108 | } |
| 109 | |
| 110 | if (Flags & MTRF_LineBreakFollows) |
| 111 | OS << "\n" ; |
| 112 | } |
| 113 | |
| 114 | //===- MatchTable ---------------------------------------------------------===// |
| 115 | |
| 116 | MatchTableRecord MatchTable::LineBreak = { |
| 117 | std::nullopt, "" /* Emit String */, 0 /* Elements */, |
| 118 | MatchTableRecord::MTRF_LineBreakFollows}; |
| 119 | |
| 120 | MatchTableRecord MatchTable::(StringRef ) { |
| 121 | return MatchTableRecord(std::nullopt, Comment, 0, |
| 122 | MatchTableRecord::MTRF_Comment); |
| 123 | } |
| 124 | |
| 125 | MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) { |
| 126 | unsigned = 0; |
| 127 | if (IndentAdjust > 0) |
| 128 | ExtraFlags |= MatchTableRecord::MTRF_Indent; |
| 129 | if (IndentAdjust < 0) |
| 130 | ExtraFlags |= MatchTableRecord::MTRF_Outdent; |
| 131 | |
| 132 | return MatchTableRecord(std::nullopt, Opcode, 1, |
| 133 | MatchTableRecord::MTRF_CommaFollows | ExtraFlags); |
| 134 | } |
| 135 | |
| 136 | MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, |
| 137 | StringRef NamedValue) { |
| 138 | return MatchTableRecord(std::nullopt, NamedValue, NumBytes, |
| 139 | MatchTableRecord::MTRF_CommaFollows); |
| 140 | } |
| 141 | |
| 142 | MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace, |
| 143 | StringRef NamedValue) { |
| 144 | return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(), |
| 145 | NumBytes, MatchTableRecord::MTRF_CommaFollows); |
| 146 | } |
| 147 | |
| 148 | MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) { |
| 149 | assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue)); |
| 150 | uint64_t UIntValue = IntValue; |
| 151 | if (NumBytes < 8) |
| 152 | UIntValue &= (UINT64_C(1) << NumBytes * 8) - 1; |
| 153 | std::string Str = llvm::to_string(Value: UIntValue); |
| 154 | if (UIntValue > INT64_MAX) |
| 155 | Str += 'u'; |
| 156 | // TODO: Could optimize this directly to save the compiler some work when |
| 157 | // building the file |
| 158 | return MatchTableRecord(std::nullopt, Str, NumBytes, |
| 159 | MatchTableRecord::MTRF_CommaFollows); |
| 160 | } |
| 161 | |
| 162 | MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) { |
| 163 | uint8_t Buffer[10]; |
| 164 | unsigned Len = encodeULEB128(Value: IntValue, p: Buffer); |
| 165 | |
| 166 | // Simple case (most common) |
| 167 | if (Len == 1) { |
| 168 | return MatchTableRecord(std::nullopt, llvm::to_string(Value: (unsigned)Buffer[0]), |
| 169 | 1, MatchTableRecord::MTRF_CommaFollows); |
| 170 | } |
| 171 | |
| 172 | // Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/ |
| 173 | std::string Str; |
| 174 | raw_string_ostream OS(Str); |
| 175 | OS << "/* " << llvm::to_string(Value: IntValue) << "(*/" ; |
| 176 | for (unsigned K = 0; K < Len; ++K) { |
| 177 | if (K) |
| 178 | OS << ", " ; |
| 179 | OS << "0x" << llvm::toHex(Input: {Buffer[K]}); |
| 180 | } |
| 181 | OS << "/*)*/" ; |
| 182 | return MatchTableRecord(std::nullopt, Str, Len, |
| 183 | MatchTableRecord::MTRF_CommaFollows | |
| 184 | MatchTableRecord::MTRF_PreEncoded); |
| 185 | } |
| 186 | |
| 187 | MatchTableRecord MatchTable::Label(unsigned LabelID) { |
| 188 | return MatchTableRecord(LabelID, "Label " + llvm::to_string(Value: LabelID), 0, |
| 189 | MatchTableRecord::MTRF_Label | |
| 190 | MatchTableRecord::MTRF_Comment | |
| 191 | MatchTableRecord::MTRF_LineBreakFollows); |
| 192 | } |
| 193 | |
| 194 | MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) { |
| 195 | return MatchTableRecord(LabelID, "Label " + llvm::to_string(Value: LabelID), 4, |
| 196 | MatchTableRecord::MTRF_JumpTarget | |
| 197 | MatchTableRecord::MTRF_Comment | |
| 198 | MatchTableRecord::MTRF_CommaFollows); |
| 199 | } |
| 200 | |
| 201 | void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; } |
| 202 | |
| 203 | void MatchTable::emitDeclaration(raw_ostream &OS) const { |
| 204 | static constexpr unsigned BaseIndent = 4; |
| 205 | unsigned Indentation = 0; |
| 206 | OS << " constexpr static uint8_t MatchTable" << ID << "[] = {" ; |
| 207 | LineBreak.emit(OS, LineBreakIsNextAfterThis: true, Table: *this); |
| 208 | |
| 209 | // We want to display the table index of each line in a consistent |
| 210 | // manner. It has to appear as a column on the left side of the table. |
| 211 | // To determine how wide the column needs to be, check how many characters |
| 212 | // we need to fit the largest possible index in the current table. |
| 213 | const unsigned NumColsForIdx = llvm::to_string(Value: CurrentSize).size(); |
| 214 | |
| 215 | unsigned CurIndex = 0; |
| 216 | const auto BeginLine = [&]() { |
| 217 | OS.indent(NumSpaces: BaseIndent); |
| 218 | std::string IdxStr = llvm::to_string(Value: CurIndex); |
| 219 | // Pad the string with spaces to keep the size of the prefix consistent. |
| 220 | OS << " /* " ; |
| 221 | OS.indent(NumSpaces: NumColsForIdx - IdxStr.size()) << IdxStr << " */ " ; |
| 222 | OS.indent(NumSpaces: Indentation); |
| 223 | }; |
| 224 | |
| 225 | BeginLine(); |
| 226 | for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) { |
| 227 | bool LineBreakIsNext = false; |
| 228 | const auto &NextI = std::next(x: I); |
| 229 | |
| 230 | if (NextI != E) { |
| 231 | if (NextI->EmitStr == "" && |
| 232 | NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows) |
| 233 | LineBreakIsNext = true; |
| 234 | } |
| 235 | |
| 236 | if (I->Flags & MatchTableRecord::MTRF_Indent) |
| 237 | Indentation += 2; |
| 238 | |
| 239 | I->emit(OS, LineBreakIsNextAfterThis: LineBreakIsNext, Table: *this); |
| 240 | if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows) |
| 241 | BeginLine(); |
| 242 | |
| 243 | if (I->Flags & MatchTableRecord::MTRF_Outdent) |
| 244 | Indentation -= 2; |
| 245 | |
| 246 | CurIndex += I->size(); |
| 247 | } |
| 248 | assert(CurIndex == CurrentSize); |
| 249 | OS << "}; // Size: " << CurrentSize << " bytes\n" ; |
| 250 | } |
| 251 | |
| 252 | } // namespace gi |
| 253 | } // namespace llvm |
| 254 | |