1fa3d789dSPierre van Houtryve //===- VarLenCodeEmitterGen.cpp - CEG for variable-length insts -----------===// 2fa3d789dSPierre van Houtryve // 3fa3d789dSPierre van Houtryve // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fa3d789dSPierre van Houtryve // See https://llvm.org/LICENSE.txt for license information. 5fa3d789dSPierre van Houtryve // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fa3d789dSPierre van Houtryve // 7fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===// 8fa3d789dSPierre van Houtryve // 9fa3d789dSPierre van Houtryve // The CodeEmitterGen component for variable-length instructions. 10fa3d789dSPierre van Houtryve // 11fa3d789dSPierre van Houtryve // The basic CodeEmitterGen is almost exclusively designed for fixed- 12fa3d789dSPierre van Houtryve // length instructions. A good analogy for its encoding scheme is how printf 13fa3d789dSPierre van Houtryve // works: The (immutable) formatting string represent the fixed values in the 14fa3d789dSPierre van Houtryve // encoded instruction. Placeholders (i.e. %something), on the other hand, 15fa3d789dSPierre van Houtryve // represent encoding for instruction operands. 16fa3d789dSPierre van Houtryve // ``` 17fa3d789dSPierre van Houtryve // printf("1101 %src 1001 %dst", <encoded value for operand `src`>, 18fa3d789dSPierre van Houtryve // <encoded value for operand `dst`>); 19fa3d789dSPierre van Houtryve // ``` 20fa3d789dSPierre van Houtryve // VarLenCodeEmitterGen in this file provides an alternative encoding scheme 21fa3d789dSPierre van Houtryve // that works more like a C++ stream operator: 22fa3d789dSPierre van Houtryve // ``` 23fa3d789dSPierre van Houtryve // OS << 0b1101; 24fa3d789dSPierre van Houtryve // if (Cond) 25fa3d789dSPierre van Houtryve // OS << OperandEncoding0; 26fa3d789dSPierre van Houtryve // OS << 0b1001 << OperandEncoding1; 27fa3d789dSPierre van Houtryve // ``` 28fa3d789dSPierre van Houtryve // You are free to concatenate arbitrary types (and sizes) of encoding 29fa3d789dSPierre van Houtryve // fragments on any bit position, bringing more flexibilities on defining 30fa3d789dSPierre van Houtryve // encoding for variable-length instructions. 31fa3d789dSPierre van Houtryve // 32fa3d789dSPierre van Houtryve // In a more specific way, instruction encoding is represented by a DAG type 33fa3d789dSPierre van Houtryve // `Inst` field. Here is an example: 34fa3d789dSPierre van Houtryve // ``` 35fa3d789dSPierre van Houtryve // dag Inst = (descend 0b1101, (operand "$src", 4), 0b1001, 36fa3d789dSPierre van Houtryve // (operand "$dst", 4)); 37fa3d789dSPierre van Houtryve // ``` 38fa3d789dSPierre van Houtryve // It represents the following instruction encoding: 39fa3d789dSPierre van Houtryve // ``` 40fa3d789dSPierre van Houtryve // MSB LSB 41fa3d789dSPierre van Houtryve // 1101<encoding for operand src>1001<encoding for operand dst> 42fa3d789dSPierre van Houtryve // ``` 43fa3d789dSPierre van Houtryve // For more details about DAG operators in the above snippet, please 44fa3d789dSPierre van Houtryve // refer to \file include/llvm/Target/Target.td. 45fa3d789dSPierre van Houtryve // 46fa3d789dSPierre van Houtryve // VarLenCodeEmitter will convert the above DAG into the same helper function 47fa3d789dSPierre van Houtryve // generated by CodeEmitter, `MCCodeEmitter::getBinaryCodeForInstr` (except 48fa3d789dSPierre van Houtryve // for few details). 49fa3d789dSPierre van Houtryve // 50fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===// 51fa3d789dSPierre van Houtryve 52fa3d789dSPierre van Houtryve #include "VarLenCodeEmitterGen.h" 53fa3d789dSPierre van Houtryve #include "CodeGenHwModes.h" 54fa3d789dSPierre van Houtryve #include "CodeGenInstruction.h" 55fa3d789dSPierre van Houtryve #include "CodeGenTarget.h" 56fa3d789dSPierre van Houtryve #include "InfoByHwMode.h" 57fa3d789dSPierre van Houtryve #include "llvm/ADT/ArrayRef.h" 58fa3d789dSPierre van Houtryve #include "llvm/ADT/DenseMap.h" 59fa3d789dSPierre van Houtryve #include "llvm/Support/raw_ostream.h" 60fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h" 61fa3d789dSPierre van Houtryve #include "llvm/TableGen/Record.h" 62fa3d789dSPierre van Houtryve 63fa3d789dSPierre van Houtryve #include <algorithm> 64fa3d789dSPierre van Houtryve 65fa3d789dSPierre van Houtryve using namespace llvm; 66fa3d789dSPierre van Houtryve 67fa3d789dSPierre van Houtryve namespace { 68fa3d789dSPierre van Houtryve 69fa3d789dSPierre van Houtryve class VarLenCodeEmitterGen { 70100b34bbSRahul Joshi const RecordKeeper &Records; 71fa3d789dSPierre van Houtryve 72fa3d789dSPierre van Houtryve // Representaton of alternative encodings used for HwModes. 73fa3d789dSPierre van Houtryve using AltEncodingTy = int; 74fa3d789dSPierre van Houtryve // Mode identifier when only one encoding is defined. 75fa3d789dSPierre van Houtryve const AltEncodingTy Universal = -1; 76fa3d789dSPierre van Houtryve // The set of alternative instruction encodings with a descriptive 77fa3d789dSPierre van Houtryve // name suffix to improve readability of the generated code. 78fa3d789dSPierre van Houtryve std::map<AltEncodingTy, std::string> Modes; 79fa3d789dSPierre van Houtryve 8037865681SRahul Joshi DenseMap<const Record *, DenseMap<AltEncodingTy, VarLenInst>> VarLenInsts; 81fa3d789dSPierre van Houtryve 82fa3d789dSPierre van Houtryve // Emit based values (i.e. fixed bits in the encoded instructions) 83fa3d789dSPierre van Houtryve void emitInstructionBaseValues( 84fa3d789dSPierre van Houtryve raw_ostream &OS, 85fa3d789dSPierre van Houtryve ArrayRef<const CodeGenInstruction *> NumberedInstructions, 86100b34bbSRahul Joshi const CodeGenTarget &Target, AltEncodingTy Mode); 87fa3d789dSPierre van Houtryve 88100b34bbSRahul Joshi std::string getInstructionCases(const Record *R, const CodeGenTarget &Target); 89100b34bbSRahul Joshi std::string getInstructionCaseForEncoding(const Record *R, AltEncodingTy Mode, 90fa3d789dSPierre van Houtryve const VarLenInst &VLI, 91100b34bbSRahul Joshi const CodeGenTarget &Target, 92100b34bbSRahul Joshi int Indent); 93fa3d789dSPierre van Houtryve 94fa3d789dSPierre van Houtryve public: 95100b34bbSRahul Joshi explicit VarLenCodeEmitterGen(const RecordKeeper &R) : Records(R) {} 96fa3d789dSPierre van Houtryve 97fa3d789dSPierre van Houtryve void run(raw_ostream &OS); 98fa3d789dSPierre van Houtryve }; 99fa3d789dSPierre van Houtryve } // end anonymous namespace 100fa3d789dSPierre van Houtryve 101fa3d789dSPierre van Houtryve // Get the name of custom encoder or decoder, if there is any. 102fa3d789dSPierre van Houtryve // Returns `{encoder name, decoder name}`. 103*62e2c7fbSRahul Joshi static std::pair<StringRef, StringRef> 104*62e2c7fbSRahul Joshi getCustomCoders(ArrayRef<const Init *> Args) { 105fa3d789dSPierre van Houtryve std::pair<StringRef, StringRef> Result; 106fa3d789dSPierre van Houtryve for (const auto *Arg : Args) { 107fa3d789dSPierre van Houtryve const auto *DI = dyn_cast<DagInit>(Arg); 108fa3d789dSPierre van Houtryve if (!DI) 109fa3d789dSPierre van Houtryve continue; 110fa3d789dSPierre van Houtryve const Init *Op = DI->getOperator(); 111fa3d789dSPierre van Houtryve if (!isa<DefInit>(Op)) 112fa3d789dSPierre van Houtryve continue; 113fa3d789dSPierre van Houtryve // syntax: `(<encoder | decoder> "function name")` 114fa3d789dSPierre van Houtryve StringRef OpName = cast<DefInit>(Op)->getDef()->getName(); 115fa3d789dSPierre van Houtryve if (OpName != "encoder" && OpName != "decoder") 116fa3d789dSPierre van Houtryve continue; 117fa3d789dSPierre van Houtryve if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0))) 118fa3d789dSPierre van Houtryve PrintFatalError("expected '" + OpName + 119fa3d789dSPierre van Houtryve "' directive to be followed by a custom function name."); 120fa3d789dSPierre van Houtryve StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue(); 121fa3d789dSPierre van Houtryve if (OpName == "encoder") 122fa3d789dSPierre van Houtryve Result.first = FuncName; 123fa3d789dSPierre van Houtryve else 124fa3d789dSPierre van Houtryve Result.second = FuncName; 125fa3d789dSPierre van Houtryve } 126fa3d789dSPierre van Houtryve return Result; 127fa3d789dSPierre van Houtryve } 128fa3d789dSPierre van Houtryve 129fa3d789dSPierre van Houtryve VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef) 130fa3d789dSPierre van Houtryve : TheDef(TheDef), NumBits(0U), HasDynamicSegment(false) { 131fa3d789dSPierre van Houtryve buildRec(DI); 132fa3d789dSPierre van Houtryve for (const auto &S : Segments) 133fa3d789dSPierre van Houtryve NumBits += S.BitWidth; 134fa3d789dSPierre van Houtryve } 135fa3d789dSPierre van Houtryve 136fa3d789dSPierre van Houtryve void VarLenInst::buildRec(const DagInit *DI) { 137fa3d789dSPierre van Houtryve assert(TheDef && "The def record is nullptr ?"); 138fa3d789dSPierre van Houtryve 139fa3d789dSPierre van Houtryve std::string Op = DI->getOperator()->getAsString(); 140fa3d789dSPierre van Houtryve 141fa3d789dSPierre van Houtryve if (Op == "ascend" || Op == "descend") { 142fa3d789dSPierre van Houtryve bool Reverse = Op == "descend"; 143fa3d789dSPierre van Houtryve int i = Reverse ? DI->getNumArgs() - 1 : 0; 144fa3d789dSPierre van Houtryve int e = Reverse ? -1 : DI->getNumArgs(); 145fa3d789dSPierre van Houtryve int s = Reverse ? -1 : 1; 146fa3d789dSPierre van Houtryve for (; i != e; i += s) { 147fa3d789dSPierre van Houtryve const Init *Arg = DI->getArg(i); 148fa3d789dSPierre van Houtryve if (const auto *BI = dyn_cast<BitsInit>(Arg)) { 149fa3d789dSPierre van Houtryve if (!BI->isComplete()) 150fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), 151fa3d789dSPierre van Houtryve "Expecting complete bits init in `" + Op + "`"); 152fa3d789dSPierre van Houtryve Segments.push_back({BI->getNumBits(), BI}); 153fa3d789dSPierre van Houtryve } else if (const auto *BI = dyn_cast<BitInit>(Arg)) { 154fa3d789dSPierre van Houtryve if (!BI->isConcrete()) 155fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), 156fa3d789dSPierre van Houtryve "Expecting concrete bit init in `" + Op + "`"); 157fa3d789dSPierre van Houtryve Segments.push_back({1, BI}); 158fa3d789dSPierre van Houtryve } else if (const auto *SubDI = dyn_cast<DagInit>(Arg)) { 159fa3d789dSPierre van Houtryve buildRec(SubDI); 160fa3d789dSPierre van Houtryve } else { 161fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), "Unrecognized type of argument in `" + 162fa3d789dSPierre van Houtryve Op + "`: " + Arg->getAsString()); 163fa3d789dSPierre van Houtryve } 164fa3d789dSPierre van Houtryve } 165fa3d789dSPierre van Houtryve } else if (Op == "operand") { 166fa3d789dSPierre van Houtryve // (operand <operand name>, <# of bits>, 167fa3d789dSPierre van Houtryve // [(encoder <custom encoder>)][, (decoder <custom decoder>)]) 168fa3d789dSPierre van Houtryve if (DI->getNumArgs() < 2) 169fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), 170fa3d789dSPierre van Houtryve "Expecting at least 2 arguments for `operand`"); 171fa3d789dSPierre van Houtryve HasDynamicSegment = true; 172fa3d789dSPierre van Houtryve const Init *OperandName = DI->getArg(0), *NumBits = DI->getArg(1); 173fa3d789dSPierre van Houtryve if (!isa<StringInit>(OperandName) || !isa<IntInit>(NumBits)) 174fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), "Invalid argument types for `operand`"); 175fa3d789dSPierre van Houtryve 176fa3d789dSPierre van Houtryve auto NumBitsVal = cast<IntInit>(NumBits)->getValue(); 177fa3d789dSPierre van Houtryve if (NumBitsVal <= 0) 178fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`"); 179fa3d789dSPierre van Houtryve 180fa3d789dSPierre van Houtryve auto [CustomEncoder, CustomDecoder] = 181fa3d789dSPierre van Houtryve getCustomCoders(DI->getArgs().slice(2)); 182fa3d789dSPierre van Houtryve Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName, 183fa3d789dSPierre van Houtryve CustomEncoder, CustomDecoder}); 184fa3d789dSPierre van Houtryve } else if (Op == "slice") { 185fa3d789dSPierre van Houtryve // (slice <operand name>, <high / low bit>, <low / high bit>, 186fa3d789dSPierre van Houtryve // [(encoder <custom encoder>)][, (decoder <custom decoder>)]) 187fa3d789dSPierre van Houtryve if (DI->getNumArgs() < 3) 188fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), 189fa3d789dSPierre van Houtryve "Expecting at least 3 arguments for `slice`"); 190fa3d789dSPierre van Houtryve HasDynamicSegment = true; 191*62e2c7fbSRahul Joshi const Init *OperandName = DI->getArg(0), *HiBit = DI->getArg(1), 192fa3d789dSPierre van Houtryve *LoBit = DI->getArg(2); 193fa3d789dSPierre van Houtryve if (!isa<StringInit>(OperandName) || !isa<IntInit>(HiBit) || 194fa3d789dSPierre van Houtryve !isa<IntInit>(LoBit)) 195fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), "Invalid argument types for `slice`"); 196fa3d789dSPierre van Houtryve 197fa3d789dSPierre van Houtryve auto HiBitVal = cast<IntInit>(HiBit)->getValue(), 198fa3d789dSPierre van Houtryve LoBitVal = cast<IntInit>(LoBit)->getValue(); 199fa3d789dSPierre van Houtryve if (HiBitVal < 0 || LoBitVal < 0) 200fa3d789dSPierre van Houtryve PrintFatalError(TheDef->getLoc(), "Invalid bit range for `slice`"); 201fa3d789dSPierre van Houtryve bool NeedSwap = false; 202fa3d789dSPierre van Houtryve unsigned NumBits = 0U; 203fa3d789dSPierre van Houtryve if (HiBitVal < LoBitVal) { 204fa3d789dSPierre van Houtryve NeedSwap = true; 205fa3d789dSPierre van Houtryve NumBits = static_cast<unsigned>(LoBitVal - HiBitVal + 1); 206fa3d789dSPierre van Houtryve } else { 207fa3d789dSPierre van Houtryve NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1); 208fa3d789dSPierre van Houtryve } 209fa3d789dSPierre van Houtryve 210fa3d789dSPierre van Houtryve auto [CustomEncoder, CustomDecoder] = 211fa3d789dSPierre van Houtryve getCustomCoders(DI->getArgs().slice(3)); 212fa3d789dSPierre van Houtryve 213fa3d789dSPierre van Houtryve if (NeedSwap) { 214fa3d789dSPierre van Houtryve // Normalization: Hi bit should always be the second argument. 215*62e2c7fbSRahul Joshi const Init *const NewArgs[] = {OperandName, LoBit, HiBit}; 216fa3d789dSPierre van Houtryve Segments.push_back({NumBits, 217fa3d789dSPierre van Houtryve DagInit::get(DI->getOperator(), nullptr, NewArgs, {}), 218fa3d789dSPierre van Houtryve CustomEncoder, CustomDecoder}); 219fa3d789dSPierre van Houtryve } else { 220fa3d789dSPierre van Houtryve Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder}); 221fa3d789dSPierre van Houtryve } 222fa3d789dSPierre van Houtryve } 223fa3d789dSPierre van Houtryve } 224fa3d789dSPierre van Houtryve 225fa3d789dSPierre van Houtryve void VarLenCodeEmitterGen::run(raw_ostream &OS) { 226fa3d789dSPierre van Houtryve CodeGenTarget Target(Records); 227fa3d789dSPierre van Houtryve 228fa3d789dSPierre van Houtryve auto NumberedInstructions = Target.getInstructionsByEnumValue(); 229fa3d789dSPierre van Houtryve 230fa3d789dSPierre van Houtryve for (const CodeGenInstruction *CGI : NumberedInstructions) { 23137865681SRahul Joshi const Record *R = CGI->TheDef; 232fa3d789dSPierre van Houtryve // Create the corresponding VarLenInst instance. 233fa3d789dSPierre van Houtryve if (R->getValueAsString("Namespace") == "TargetOpcode" || 234fa3d789dSPierre van Houtryve R->getValueAsBit("isPseudo")) 235fa3d789dSPierre van Houtryve continue; 236fa3d789dSPierre van Houtryve 237fa3d789dSPierre van Houtryve // Setup alternative encodings according to HwModes 238fa3d789dSPierre van Houtryve if (const RecordVal *RV = R->getValue("EncodingInfos")) { 239fa3d789dSPierre van Houtryve if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) { 240fa3d789dSPierre van Houtryve const CodeGenHwModes &HWM = Target.getHwModes(); 241fa3d789dSPierre van Houtryve EncodingInfoByHwMode EBM(DI->getDef(), HWM); 242100b34bbSRahul Joshi for (const auto [Mode, EncodingDef] : EBM) { 243fa3d789dSPierre van Houtryve Modes.insert({Mode, "_" + HWM.getMode(Mode).Name.str()}); 244985600dcSRahul Joshi const RecordVal *RV = EncodingDef->getValue("Inst"); 245*62e2c7fbSRahul Joshi const DagInit *DI = cast<DagInit>(RV->getValue()); 246fa3d789dSPierre van Houtryve VarLenInsts[R].insert({Mode, VarLenInst(DI, RV)}); 247fa3d789dSPierre van Houtryve } 248fa3d789dSPierre van Houtryve continue; 249fa3d789dSPierre van Houtryve } 250fa3d789dSPierre van Houtryve } 25137865681SRahul Joshi const RecordVal *RV = R->getValue("Inst"); 252100b34bbSRahul Joshi const DagInit *DI = cast<DagInit>(RV->getValue()); 253fa3d789dSPierre van Houtryve VarLenInsts[R].insert({Universal, VarLenInst(DI, RV)}); 254fa3d789dSPierre van Houtryve } 255fa3d789dSPierre van Houtryve 256fa3d789dSPierre van Houtryve if (Modes.empty()) 257fa3d789dSPierre van Houtryve Modes.insert({Universal, ""}); // Base case, skip suffix. 258fa3d789dSPierre van Houtryve 259fa3d789dSPierre van Houtryve // Emit function declaration 260fa3d789dSPierre van Houtryve OS << "void " << Target.getName() 261fa3d789dSPierre van Houtryve << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" 262fa3d789dSPierre van Houtryve << " SmallVectorImpl<MCFixup> &Fixups,\n" 263fa3d789dSPierre van Houtryve << " APInt &Inst,\n" 264fa3d789dSPierre van Houtryve << " APInt &Scratch,\n" 265fa3d789dSPierre van Houtryve << " const MCSubtargetInfo &STI) const {\n"; 266fa3d789dSPierre van Houtryve 267fa3d789dSPierre van Houtryve // Emit instruction base values 268fa3d789dSPierre van Houtryve for (const auto &Mode : Modes) 269fa3d789dSPierre van Houtryve emitInstructionBaseValues(OS, NumberedInstructions, Target, Mode.first); 270fa3d789dSPierre van Houtryve 271fa3d789dSPierre van Houtryve if (Modes.size() > 1) { 272fa3d789dSPierre van Houtryve OS << " unsigned Mode = STI.getHwMode();\n"; 273fa3d789dSPierre van Houtryve } 274fa3d789dSPierre van Houtryve 275fa3d789dSPierre van Houtryve for (const auto &Mode : Modes) { 276fa3d789dSPierre van Houtryve // Emit helper function to retrieve base values. 277fa3d789dSPierre van Houtryve OS << " auto getInstBits" << Mode.second 278fa3d789dSPierre van Houtryve << " = [&](unsigned Opcode) -> APInt {\n" 279fa3d789dSPierre van Houtryve << " unsigned NumBits = Index" << Mode.second << "[Opcode][0];\n" 280fa3d789dSPierre van Houtryve << " if (!NumBits)\n" 281fa3d789dSPierre van Houtryve << " return APInt::getZeroWidth();\n" 282fa3d789dSPierre van Houtryve << " unsigned Idx = Index" << Mode.second << "[Opcode][1];\n" 283fa3d789dSPierre van Houtryve << " ArrayRef<uint64_t> Data(&InstBits" << Mode.second << "[Idx], " 284fa3d789dSPierre van Houtryve << "APInt::getNumWords(NumBits));\n" 285fa3d789dSPierre van Houtryve << " return APInt(NumBits, Data);\n" 286fa3d789dSPierre van Houtryve << " };\n"; 287fa3d789dSPierre van Houtryve } 288fa3d789dSPierre van Houtryve 289fa3d789dSPierre van Houtryve // Map to accumulate all the cases. 290fa3d789dSPierre van Houtryve std::map<std::string, std::vector<std::string>> CaseMap; 291fa3d789dSPierre van Houtryve 292fa3d789dSPierre van Houtryve // Construct all cases statement for each opcode 293100b34bbSRahul Joshi for (const Record *R : Records.getAllDerivedDefinitions("Instruction")) { 294fa3d789dSPierre van Houtryve if (R->getValueAsString("Namespace") == "TargetOpcode" || 295fa3d789dSPierre van Houtryve R->getValueAsBit("isPseudo")) 296fa3d789dSPierre van Houtryve continue; 297fa3d789dSPierre van Houtryve std::string InstName = 298fa3d789dSPierre van Houtryve (R->getValueAsString("Namespace") + "::" + R->getName()).str(); 299fa3d789dSPierre van Houtryve std::string Case = getInstructionCases(R, Target); 300fa3d789dSPierre van Houtryve 301fa3d789dSPierre van Houtryve CaseMap[Case].push_back(std::move(InstName)); 302fa3d789dSPierre van Houtryve } 303fa3d789dSPierre van Houtryve 304fa3d789dSPierre van Houtryve // Emit initial function code 305fa3d789dSPierre van Houtryve OS << " const unsigned opcode = MI.getOpcode();\n" 306fa3d789dSPierre van Houtryve << " switch (opcode) {\n"; 307fa3d789dSPierre van Houtryve 308fa3d789dSPierre van Houtryve // Emit each case statement 309fa3d789dSPierre van Houtryve for (const auto &C : CaseMap) { 310fa3d789dSPierre van Houtryve const std::string &Case = C.first; 311fa3d789dSPierre van Houtryve const auto &InstList = C.second; 312fa3d789dSPierre van Houtryve 313fa3d789dSPierre van Houtryve ListSeparator LS("\n"); 314fa3d789dSPierre van Houtryve for (const auto &InstName : InstList) 315fa3d789dSPierre van Houtryve OS << LS << " case " << InstName << ":"; 316fa3d789dSPierre van Houtryve 317fa3d789dSPierre van Houtryve OS << " {\n"; 318fa3d789dSPierre van Houtryve OS << Case; 319fa3d789dSPierre van Houtryve OS << " break;\n" 320fa3d789dSPierre van Houtryve << " }\n"; 321fa3d789dSPierre van Houtryve } 322fa3d789dSPierre van Houtryve // Default case: unhandled opcode 323fa3d789dSPierre van Houtryve OS << " default:\n" 324fa3d789dSPierre van Houtryve << " std::string msg;\n" 325fa3d789dSPierre van Houtryve << " raw_string_ostream Msg(msg);\n" 326fa3d789dSPierre van Houtryve << " Msg << \"Not supported instr: \" << MI;\n" 327fa3d789dSPierre van Houtryve << " report_fatal_error(Msg.str().c_str());\n" 328fa3d789dSPierre van Houtryve << " }\n"; 329fa3d789dSPierre van Houtryve OS << "}\n\n"; 330fa3d789dSPierre van Houtryve } 331fa3d789dSPierre van Houtryve 332fa3d789dSPierre van Houtryve static void emitInstBits(raw_ostream &IS, raw_ostream &SS, const APInt &Bits, 333fa3d789dSPierre van Houtryve unsigned &Index) { 334fa3d789dSPierre van Houtryve if (!Bits.getNumWords()) { 335fa3d789dSPierre van Houtryve IS.indent(4) << "{/*NumBits*/0, /*Index*/0},"; 336fa3d789dSPierre van Houtryve return; 337fa3d789dSPierre van Houtryve } 338fa3d789dSPierre van Houtryve 339fa3d789dSPierre van Houtryve IS.indent(4) << "{/*NumBits*/" << Bits.getBitWidth() << ", " << "/*Index*/" 340fa3d789dSPierre van Houtryve << Index << "},"; 341fa3d789dSPierre van Houtryve 342fa3d789dSPierre van Houtryve SS.indent(4); 343fa3d789dSPierre van Houtryve for (unsigned I = 0; I < Bits.getNumWords(); ++I, ++Index) 344fa3d789dSPierre van Houtryve SS << "UINT64_C(" << utostr(Bits.getRawData()[I]) << "),"; 345fa3d789dSPierre van Houtryve } 346fa3d789dSPierre van Houtryve 347fa3d789dSPierre van Houtryve void VarLenCodeEmitterGen::emitInstructionBaseValues( 348fa3d789dSPierre van Houtryve raw_ostream &OS, ArrayRef<const CodeGenInstruction *> NumberedInstructions, 349100b34bbSRahul Joshi const CodeGenTarget &Target, AltEncodingTy Mode) { 350fa3d789dSPierre van Houtryve std::string IndexArray, StorageArray; 351fa3d789dSPierre van Houtryve raw_string_ostream IS(IndexArray), SS(StorageArray); 352fa3d789dSPierre van Houtryve 353fa3d789dSPierre van Houtryve IS << " static const unsigned Index" << Modes[Mode] << "[][2] = {\n"; 354fa3d789dSPierre van Houtryve SS << " static const uint64_t InstBits" << Modes[Mode] << "[] = {\n"; 355fa3d789dSPierre van Houtryve 356fa3d789dSPierre van Houtryve unsigned NumFixedValueWords = 0U; 357fa3d789dSPierre van Houtryve for (const CodeGenInstruction *CGI : NumberedInstructions) { 35837865681SRahul Joshi const Record *R = CGI->TheDef; 359fa3d789dSPierre van Houtryve 360fa3d789dSPierre van Houtryve if (R->getValueAsString("Namespace") == "TargetOpcode" || 361fa3d789dSPierre van Houtryve R->getValueAsBit("isPseudo")) { 362fa3d789dSPierre van Houtryve IS.indent(4) << "{/*NumBits*/0, /*Index*/0},\n"; 363fa3d789dSPierre van Houtryve continue; 364fa3d789dSPierre van Houtryve } 365fa3d789dSPierre van Houtryve 366fa3d789dSPierre van Houtryve const auto InstIt = VarLenInsts.find(R); 367fa3d789dSPierre van Houtryve if (InstIt == VarLenInsts.end()) 368fa3d789dSPierre van Houtryve PrintFatalError(R, "VarLenInst not found for this record"); 369fa3d789dSPierre van Houtryve auto ModeIt = InstIt->second.find(Mode); 370fa3d789dSPierre van Houtryve if (ModeIt == InstIt->second.end()) 371fa3d789dSPierre van Houtryve ModeIt = InstIt->second.find(Universal); 372fa3d789dSPierre van Houtryve if (ModeIt == InstIt->second.end()) { 373fa3d789dSPierre van Houtryve IS.indent(4) << "{/*NumBits*/0, /*Index*/0},\t" << "// " << R->getName() 374fa3d789dSPierre van Houtryve << " no encoding\n"; 375fa3d789dSPierre van Houtryve continue; 376fa3d789dSPierre van Houtryve } 377fa3d789dSPierre van Houtryve const VarLenInst &VLI = ModeIt->second; 378fa3d789dSPierre van Houtryve unsigned i = 0U, BitWidth = VLI.size(); 379fa3d789dSPierre van Houtryve 380fa3d789dSPierre van Houtryve // Start by filling in fixed values. 381fa3d789dSPierre van Houtryve APInt Value(BitWidth, 0); 382fa3d789dSPierre van Houtryve auto SI = VLI.begin(), SE = VLI.end(); 383fa3d789dSPierre van Houtryve // Scan through all the segments that have fixed-bits values. 384fa3d789dSPierre van Houtryve while (i < BitWidth && SI != SE) { 385fa3d789dSPierre van Houtryve unsigned SegmentNumBits = SI->BitWidth; 386fa3d789dSPierre van Houtryve if (const auto *BI = dyn_cast<BitsInit>(SI->Value)) { 387fa3d789dSPierre van Houtryve for (unsigned Idx = 0U; Idx != SegmentNumBits; ++Idx) { 388fa3d789dSPierre van Houtryve auto *B = cast<BitInit>(BI->getBit(Idx)); 389fa3d789dSPierre van Houtryve Value.setBitVal(i + Idx, B->getValue()); 390fa3d789dSPierre van Houtryve } 391fa3d789dSPierre van Houtryve } 392fa3d789dSPierre van Houtryve if (const auto *BI = dyn_cast<BitInit>(SI->Value)) 393fa3d789dSPierre van Houtryve Value.setBitVal(i, BI->getValue()); 394fa3d789dSPierre van Houtryve 395fa3d789dSPierre van Houtryve i += SegmentNumBits; 396fa3d789dSPierre van Houtryve ++SI; 397fa3d789dSPierre van Houtryve } 398fa3d789dSPierre van Houtryve 399fa3d789dSPierre van Houtryve emitInstBits(IS, SS, Value, NumFixedValueWords); 400fa3d789dSPierre van Houtryve IS << '\t' << "// " << R->getName() << "\n"; 401fa3d789dSPierre van Houtryve if (Value.getNumWords()) 402fa3d789dSPierre van Houtryve SS << '\t' << "// " << R->getName() << "\n"; 403fa3d789dSPierre van Houtryve } 404fa3d789dSPierre van Houtryve IS.indent(4) << "{/*NumBits*/0, /*Index*/0}\n };\n"; 405fa3d789dSPierre van Houtryve SS.indent(4) << "UINT64_C(0)\n };\n"; 406fa3d789dSPierre van Houtryve 407caf26b94SYoungsuk Kim OS << IndexArray << StorageArray; 408fa3d789dSPierre van Houtryve } 409fa3d789dSPierre van Houtryve 410100b34bbSRahul Joshi std::string 411100b34bbSRahul Joshi VarLenCodeEmitterGen::getInstructionCases(const Record *R, 412100b34bbSRahul Joshi const CodeGenTarget &Target) { 413fa3d789dSPierre van Houtryve auto It = VarLenInsts.find(R); 414fa3d789dSPierre van Houtryve if (It == VarLenInsts.end()) 415fa3d789dSPierre van Houtryve PrintFatalError(R, "Parsed encoding record not found"); 416fa3d789dSPierre van Houtryve const auto &Map = It->second; 417fa3d789dSPierre van Houtryve 418fa3d789dSPierre van Houtryve // Is this instructions encoding universal (same for all modes)? 419fa3d789dSPierre van Houtryve // Allways true if there is only one mode. 420fa3d789dSPierre van Houtryve if (Map.size() == 1 && Map.begin()->first == Universal) { 421fa3d789dSPierre van Houtryve // Universal, just pick the first mode. 422fa3d789dSPierre van Houtryve AltEncodingTy Mode = Modes.begin()->first; 423fa3d789dSPierre van Houtryve const auto &Encoding = Map.begin()->second; 424100b34bbSRahul Joshi return getInstructionCaseForEncoding(R, Mode, Encoding, Target, 425100b34bbSRahul Joshi /*Indent=*/6); 426fa3d789dSPierre van Houtryve } 427fa3d789dSPierre van Houtryve 428fa3d789dSPierre van Houtryve std::string Case; 429fa3d789dSPierre van Houtryve Case += " switch (Mode) {\n"; 430fa3d789dSPierre van Houtryve Case += " default: llvm_unreachable(\"Unhandled Mode\");\n"; 431fa3d789dSPierre van Houtryve for (const auto &Mode : Modes) { 432fa3d789dSPierre van Houtryve Case += " case " + itostr(Mode.first) + ": {\n"; 433fa3d789dSPierre van Houtryve const auto &It = Map.find(Mode.first); 434fa3d789dSPierre van Houtryve if (It == Map.end()) { 435fa3d789dSPierre van Houtryve Case += 436fa3d789dSPierre van Houtryve " llvm_unreachable(\"Undefined encoding in this mode\");\n"; 437fa3d789dSPierre van Houtryve } else { 438100b34bbSRahul Joshi Case += getInstructionCaseForEncoding(R, It->first, It->second, Target, 439100b34bbSRahul Joshi /*Indent=*/8); 440fa3d789dSPierre van Houtryve } 441fa3d789dSPierre van Houtryve Case += " break;\n"; 442fa3d789dSPierre van Houtryve Case += " }\n"; 443fa3d789dSPierre van Houtryve } 444fa3d789dSPierre van Houtryve Case += " }\n"; 445fa3d789dSPierre van Houtryve return Case; 446fa3d789dSPierre van Houtryve } 447fa3d789dSPierre van Houtryve 448fa3d789dSPierre van Houtryve std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding( 449100b34bbSRahul Joshi const Record *R, AltEncodingTy Mode, const VarLenInst &VLI, 450100b34bbSRahul Joshi const CodeGenTarget &Target, int Indent) { 451fa3d789dSPierre van Houtryve CodeGenInstruction &CGI = Target.getInstruction(R); 452fa3d789dSPierre van Houtryve 453fa3d789dSPierre van Houtryve std::string Case; 454fa3d789dSPierre van Houtryve raw_string_ostream SS(Case); 455fa3d789dSPierre van Houtryve // Populate based value. 456100b34bbSRahul Joshi SS.indent(Indent) << "Inst = getInstBits" << Modes[Mode] << "(opcode);\n"; 457fa3d789dSPierre van Houtryve 458fa3d789dSPierre van Houtryve // Process each segment in VLI. 459fa3d789dSPierre van Houtryve size_t Offset = 0U; 460fa3d789dSPierre van Houtryve unsigned HighScratchAccess = 0U; 461fa3d789dSPierre van Houtryve for (const auto &ES : VLI) { 462fa3d789dSPierre van Houtryve unsigned NumBits = ES.BitWidth; 463fa3d789dSPierre van Houtryve const Init *Val = ES.Value; 464fa3d789dSPierre van Houtryve // If it's a StringInit or DagInit, it's a reference to an operand 465fa3d789dSPierre van Houtryve // or part of an operand. 466fa3d789dSPierre van Houtryve if (isa<StringInit>(Val) || isa<DagInit>(Val)) { 467fa3d789dSPierre van Houtryve StringRef OperandName; 468fa3d789dSPierre van Houtryve unsigned LoBit = 0U; 469fa3d789dSPierre van Houtryve if (const auto *SV = dyn_cast<StringInit>(Val)) { 470fa3d789dSPierre van Houtryve OperandName = SV->getValue(); 471fa3d789dSPierre van Houtryve } else { 472fa3d789dSPierre van Houtryve // Normalized: (slice <operand name>, <high bit>, <low bit>) 473fa3d789dSPierre van Houtryve const auto *DV = cast<DagInit>(Val); 474fa3d789dSPierre van Houtryve OperandName = cast<StringInit>(DV->getArg(0))->getValue(); 475fa3d789dSPierre van Houtryve LoBit = static_cast<unsigned>(cast<IntInit>(DV->getArg(2))->getValue()); 476fa3d789dSPierre van Houtryve } 477fa3d789dSPierre van Houtryve 478fa3d789dSPierre van Houtryve auto OpIdx = CGI.Operands.ParseOperandName(OperandName); 479fa3d789dSPierre van Houtryve unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx); 480fa3d789dSPierre van Houtryve StringRef CustomEncoder = 481fa3d789dSPierre van Houtryve CGI.Operands[OpIdx.first].EncoderMethodNames[OpIdx.second]; 482fa3d789dSPierre van Houtryve if (ES.CustomEncoder.size()) 483fa3d789dSPierre van Houtryve CustomEncoder = ES.CustomEncoder; 484fa3d789dSPierre van Houtryve 485100b34bbSRahul Joshi SS.indent(Indent) << "Scratch.clearAllBits();\n"; 486100b34bbSRahul Joshi SS.indent(Indent) << "// op: " << OperandName.drop_front(1) << "\n"; 487fa3d789dSPierre van Houtryve if (CustomEncoder.empty()) 488100b34bbSRahul Joshi SS.indent(Indent) << "getMachineOpValue(MI, MI.getOperand(" 489fa3d789dSPierre van Houtryve << utostr(FlatOpIdx) << ")"; 490fa3d789dSPierre van Houtryve else 491100b34bbSRahul Joshi SS.indent(Indent) << CustomEncoder << "(MI, /*OpIdx=*/" 492100b34bbSRahul Joshi << utostr(FlatOpIdx); 493fa3d789dSPierre van Houtryve 494fa3d789dSPierre van Houtryve SS << ", /*Pos=*/" << utostr(Offset) << ", Scratch, Fixups, STI);\n"; 495fa3d789dSPierre van Houtryve 496100b34bbSRahul Joshi SS.indent(Indent) << "Inst.insertBits(" 497100b34bbSRahul Joshi << "Scratch.extractBits(" << utostr(NumBits) << ", " 498100b34bbSRahul Joshi << utostr(LoBit) << ")" 499100b34bbSRahul Joshi << ", " << Offset << ");\n"; 500fa3d789dSPierre van Houtryve 501fa3d789dSPierre van Houtryve HighScratchAccess = std::max(HighScratchAccess, NumBits + LoBit); 502fa3d789dSPierre van Houtryve } 503fa3d789dSPierre van Houtryve Offset += NumBits; 504fa3d789dSPierre van Houtryve } 505fa3d789dSPierre van Houtryve 506fa3d789dSPierre van Houtryve StringRef PostEmitter = R->getValueAsString("PostEncoderMethod"); 507fa3d789dSPierre van Houtryve if (!PostEmitter.empty()) 508100b34bbSRahul Joshi SS.indent(Indent) << "Inst = " << PostEmitter << "(MI, Inst, STI);\n"; 509fa3d789dSPierre van Houtryve 510fa3d789dSPierre van Houtryve // Resize the scratch buffer if it's to small. 511fa3d789dSPierre van Houtryve std::string ScratchResizeStr; 512fa3d789dSPierre van Houtryve if (VLI.size() && !VLI.isFixedValueOnly()) { 513fa3d789dSPierre van Houtryve raw_string_ostream RS(ScratchResizeStr); 514100b34bbSRahul Joshi RS.indent(Indent) << "if (Scratch.getBitWidth() < " << HighScratchAccess 515fa3d789dSPierre van Houtryve << ") { Scratch = Scratch.zext(" << HighScratchAccess 516fa3d789dSPierre van Houtryve << "); }\n"; 517fa3d789dSPierre van Houtryve } 518fa3d789dSPierre van Houtryve 519fa3d789dSPierre van Houtryve return ScratchResizeStr + Case; 520fa3d789dSPierre van Houtryve } 521fa3d789dSPierre van Houtryve 522100b34bbSRahul Joshi void llvm::emitVarLenCodeEmitter(const RecordKeeper &R, raw_ostream &OS) { 523fa3d789dSPierre van Houtryve VarLenCodeEmitterGen(R).run(OS); 524fa3d789dSPierre van Houtryve } 525