1fa3d789dSPierre van Houtryve //===- Patterns.cpp --------------------------------------------*- C++ -*-===// 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 #include "Patterns.h" 10fa3d789dSPierre van Houtryve #include "Basic/CodeGenIntrinsics.h" 11fa3d789dSPierre van Houtryve #include "CXXPredicates.h" 12fa3d789dSPierre van Houtryve #include "CodeExpander.h" 13fa3d789dSPierre van Houtryve #include "CodeExpansions.h" 14fa3d789dSPierre van Houtryve #include "Common/CodeGenInstruction.h" 15fa3d789dSPierre van Houtryve #include "llvm/ADT/StringSet.h" 16fa3d789dSPierre van Houtryve #include "llvm/Support/Debug.h" 17fa3d789dSPierre van Houtryve #include "llvm/Support/raw_ostream.h" 18fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h" 19fa3d789dSPierre van Houtryve #include "llvm/TableGen/Record.h" 20fa3d789dSPierre van Houtryve 21fa3d789dSPierre van Houtryve namespace llvm { 22fa3d789dSPierre van Houtryve namespace gi { 23fa3d789dSPierre van Houtryve 24fa3d789dSPierre van Houtryve //===- PatternType --------------------------------------------------------===// 25fa3d789dSPierre van Houtryve 26fa3d789dSPierre van Houtryve std::optional<PatternType> PatternType::get(ArrayRef<SMLoc> DiagLoc, 27fa3d789dSPierre van Houtryve const Record *R, Twine DiagCtx) { 28fa3d789dSPierre van Houtryve assert(R); 29fa3d789dSPierre van Houtryve if (R->isSubClassOf("ValueType")) { 30fa3d789dSPierre van Houtryve PatternType PT(PT_ValueType); 31fa3d789dSPierre van Houtryve PT.Data.Def = R; 32fa3d789dSPierre van Houtryve return PT; 33fa3d789dSPierre van Houtryve } 34fa3d789dSPierre van Houtryve 35fa3d789dSPierre van Houtryve if (R->isSubClassOf(TypeOfClassName)) { 36fa3d789dSPierre van Houtryve auto RawOpName = R->getValueAsString("OpName"); 37fa3d789dSPierre van Houtryve if (!RawOpName.starts_with("$")) { 38fa3d789dSPierre van Houtryve PrintError(DiagLoc, DiagCtx + ": invalid operand name format '" + 39fa3d789dSPierre van Houtryve RawOpName + "' in " + TypeOfClassName + 40fa3d789dSPierre van Houtryve ": expected '$' followed by an operand name"); 41fa3d789dSPierre van Houtryve return std::nullopt; 42fa3d789dSPierre van Houtryve } 43fa3d789dSPierre van Houtryve 44fa3d789dSPierre van Houtryve PatternType PT(PT_TypeOf); 45fa3d789dSPierre van Houtryve PT.Data.Str = RawOpName.drop_front(1); 46fa3d789dSPierre van Houtryve return PT; 47fa3d789dSPierre van Houtryve } 48fa3d789dSPierre van Houtryve 49972c0292SPierre van Houtryve if (R->isSubClassOf(VariadicClassName)) { 50972c0292SPierre van Houtryve const int64_t Min = R->getValueAsInt("MinArgs"); 51972c0292SPierre van Houtryve const int64_t Max = R->getValueAsInt("MaxArgs"); 52972c0292SPierre van Houtryve 53972c0292SPierre van Houtryve if (Min == 0) { 54972c0292SPierre van Houtryve PrintError( 55972c0292SPierre van Houtryve DiagLoc, 56972c0292SPierre van Houtryve DiagCtx + 57972c0292SPierre van Houtryve ": minimum number of arguments must be greater than zero in " + 58972c0292SPierre van Houtryve VariadicClassName); 59972c0292SPierre van Houtryve return std::nullopt; 60972c0292SPierre van Houtryve } 61972c0292SPierre van Houtryve 62972c0292SPierre van Houtryve if (Max <= Min && Max != 0) { 63972c0292SPierre van Houtryve PrintError(DiagLoc, DiagCtx + ": maximum number of arguments (" + 64972c0292SPierre van Houtryve Twine(Max) + 65972c0292SPierre van Houtryve ") must be zero, or greater " 66972c0292SPierre van Houtryve "than the minimum number of arguments (" + 67972c0292SPierre van Houtryve Twine(Min) + ") in " + VariadicClassName); 68972c0292SPierre van Houtryve return std::nullopt; 69972c0292SPierre van Houtryve } 70972c0292SPierre van Houtryve 71972c0292SPierre van Houtryve PatternType PT(PT_VariadicPack); 72972c0292SPierre van Houtryve PT.Data.VPTI = {unsigned(Min), unsigned(Max)}; 73972c0292SPierre van Houtryve return PT; 74972c0292SPierre van Houtryve } 75972c0292SPierre van Houtryve 76fa3d789dSPierre van Houtryve PrintError(DiagLoc, DiagCtx + ": unknown type '" + R->getName() + "'"); 77fa3d789dSPierre van Houtryve return std::nullopt; 78fa3d789dSPierre van Houtryve } 79fa3d789dSPierre van Houtryve 80fa3d789dSPierre van Houtryve PatternType PatternType::getTypeOf(StringRef OpName) { 81fa3d789dSPierre van Houtryve PatternType PT(PT_TypeOf); 82fa3d789dSPierre van Houtryve PT.Data.Str = OpName; 83fa3d789dSPierre van Houtryve return PT; 84fa3d789dSPierre van Houtryve } 85fa3d789dSPierre van Houtryve 86fa3d789dSPierre van Houtryve StringRef PatternType::getTypeOfOpName() const { 87fa3d789dSPierre van Houtryve assert(isTypeOf()); 88fa3d789dSPierre van Houtryve return Data.Str; 89fa3d789dSPierre van Houtryve } 90fa3d789dSPierre van Houtryve 91fa3d789dSPierre van Houtryve const Record *PatternType::getLLTRecord() const { 92fa3d789dSPierre van Houtryve assert(isLLT()); 93fa3d789dSPierre van Houtryve return Data.Def; 94fa3d789dSPierre van Houtryve } 95fa3d789dSPierre van Houtryve 96972c0292SPierre van Houtryve VariadicPackTypeInfo PatternType::getVariadicPackTypeInfo() const { 97972c0292SPierre van Houtryve assert(isVariadicPack()); 98972c0292SPierre van Houtryve return Data.VPTI; 99972c0292SPierre van Houtryve } 100972c0292SPierre van Houtryve 101fa3d789dSPierre van Houtryve bool PatternType::operator==(const PatternType &Other) const { 102fa3d789dSPierre van Houtryve if (Kind != Other.Kind) 103fa3d789dSPierre van Houtryve return false; 104fa3d789dSPierre van Houtryve 105fa3d789dSPierre van Houtryve switch (Kind) { 106fa3d789dSPierre van Houtryve case PT_None: 107fa3d789dSPierre van Houtryve return true; 108fa3d789dSPierre van Houtryve case PT_ValueType: 109fa3d789dSPierre van Houtryve return Data.Def == Other.Data.Def; 110fa3d789dSPierre van Houtryve case PT_TypeOf: 111fa3d789dSPierre van Houtryve return Data.Str == Other.Data.Str; 112972c0292SPierre van Houtryve case PT_VariadicPack: 113972c0292SPierre van Houtryve return Data.VPTI == Other.Data.VPTI; 114fa3d789dSPierre van Houtryve } 115fa3d789dSPierre van Houtryve 116fa3d789dSPierre van Houtryve llvm_unreachable("Unknown Type Kind"); 117fa3d789dSPierre van Houtryve } 118fa3d789dSPierre van Houtryve 119fa3d789dSPierre van Houtryve std::string PatternType::str() const { 120fa3d789dSPierre van Houtryve switch (Kind) { 121fa3d789dSPierre van Houtryve case PT_None: 122fa3d789dSPierre van Houtryve return ""; 123fa3d789dSPierre van Houtryve case PT_ValueType: 124fa3d789dSPierre van Houtryve return Data.Def->getName().str(); 125fa3d789dSPierre van Houtryve case PT_TypeOf: 126fa3d789dSPierre van Houtryve return (TypeOfClassName + "<$" + getTypeOfOpName() + ">").str(); 127972c0292SPierre van Houtryve case PT_VariadicPack: 128972c0292SPierre van Houtryve return (VariadicClassName + "<" + Twine(Data.VPTI.Min) + "," + 129972c0292SPierre van Houtryve Twine(Data.VPTI.Max) + ">") 130972c0292SPierre van Houtryve .str(); 131fa3d789dSPierre van Houtryve } 132fa3d789dSPierre van Houtryve 133fa3d789dSPierre van Houtryve llvm_unreachable("Unknown type!"); 134fa3d789dSPierre van Houtryve } 135fa3d789dSPierre van Houtryve 136fa3d789dSPierre van Houtryve //===- Pattern ------------------------------------------------------------===// 137fa3d789dSPierre van Houtryve 138fa3d789dSPierre van Houtryve void Pattern::dump() const { return print(dbgs()); } 139fa3d789dSPierre van Houtryve 140fa3d789dSPierre van Houtryve const char *Pattern::getKindName() const { 141fa3d789dSPierre van Houtryve switch (Kind) { 142fa3d789dSPierre van Houtryve case K_AnyOpcode: 143fa3d789dSPierre van Houtryve return "AnyOpcodePattern"; 144fa3d789dSPierre van Houtryve case K_CXX: 145fa3d789dSPierre van Houtryve return "CXXPattern"; 146fa3d789dSPierre van Houtryve case K_CodeGenInstruction: 147fa3d789dSPierre van Houtryve return "CodeGenInstructionPattern"; 148fa3d789dSPierre van Houtryve case K_PatFrag: 149fa3d789dSPierre van Houtryve return "PatFragPattern"; 150fa3d789dSPierre van Houtryve case K_Builtin: 151fa3d789dSPierre van Houtryve return "BuiltinPattern"; 152fa3d789dSPierre van Houtryve } 153fa3d789dSPierre van Houtryve 154fa3d789dSPierre van Houtryve llvm_unreachable("unknown pattern kind!"); 155fa3d789dSPierre van Houtryve } 156fa3d789dSPierre van Houtryve 157fa3d789dSPierre van Houtryve void Pattern::printImpl(raw_ostream &OS, bool PrintName, 158fa3d789dSPierre van Houtryve function_ref<void()> ContentPrinter) const { 159fa3d789dSPierre van Houtryve OS << "(" << getKindName() << " "; 160fa3d789dSPierre van Houtryve if (PrintName) 161fa3d789dSPierre van Houtryve OS << "name:" << getName() << " "; 162fa3d789dSPierre van Houtryve ContentPrinter(); 163fa3d789dSPierre van Houtryve OS << ")"; 164fa3d789dSPierre van Houtryve } 165fa3d789dSPierre van Houtryve 166fa3d789dSPierre van Houtryve //===- AnyOpcodePattern ---------------------------------------------------===// 167fa3d789dSPierre van Houtryve 168fa3d789dSPierre van Houtryve void AnyOpcodePattern::print(raw_ostream &OS, bool PrintName) const { 169fa3d789dSPierre van Houtryve printImpl(OS, PrintName, [&OS, this]() { 170fa3d789dSPierre van Houtryve OS << "[" 171fa3d789dSPierre van Houtryve << join(map_range(Insts, 172fa3d789dSPierre van Houtryve [](const auto *I) { return I->TheDef->getName(); }), 173fa3d789dSPierre van Houtryve ", ") 174fa3d789dSPierre van Houtryve << "]"; 175fa3d789dSPierre van Houtryve }); 176fa3d789dSPierre van Houtryve } 177fa3d789dSPierre van Houtryve 178fa3d789dSPierre van Houtryve //===- CXXPattern ---------------------------------------------------------===// 179fa3d789dSPierre van Houtryve 180fa3d789dSPierre van Houtryve CXXPattern::CXXPattern(const StringInit &Code, StringRef Name) 181fa3d789dSPierre van Houtryve : CXXPattern(Code.getAsUnquotedString(), Name) {} 182fa3d789dSPierre van Houtryve 183fa3d789dSPierre van Houtryve const CXXPredicateCode & 184fa3d789dSPierre van Houtryve CXXPattern::expandCode(const CodeExpansions &CE, ArrayRef<SMLoc> Locs, 185fa3d789dSPierre van Houtryve function_ref<void(raw_ostream &)> AddComment) const { 1867d810623SPierre van Houtryve assert(!IsApply && "'apply' CXX patterns should be handled differently!"); 1877d810623SPierre van Houtryve 188fa3d789dSPierre van Houtryve std::string Result; 189fa3d789dSPierre van Houtryve raw_string_ostream OS(Result); 190fa3d789dSPierre van Houtryve 191fa3d789dSPierre van Houtryve if (AddComment) 192fa3d789dSPierre van Houtryve AddComment(OS); 193fa3d789dSPierre van Houtryve 194fa3d789dSPierre van Houtryve CodeExpander Expander(RawCode, CE, Locs, /*ShowExpansions*/ false); 195fa3d789dSPierre van Houtryve Expander.emit(OS); 196fa3d789dSPierre van Houtryve return CXXPredicateCode::getMatchCode(std::move(Result)); 197fa3d789dSPierre van Houtryve } 198fa3d789dSPierre van Houtryve 199fa3d789dSPierre van Houtryve void CXXPattern::print(raw_ostream &OS, bool PrintName) const { 200fa3d789dSPierre van Houtryve printImpl(OS, PrintName, [&OS, this] { 201fa3d789dSPierre van Houtryve OS << (IsApply ? "apply" : "match") << " code:\""; 202fa3d789dSPierre van Houtryve printEscapedString(getRawCode(), OS); 203fa3d789dSPierre van Houtryve OS << "\""; 204fa3d789dSPierre van Houtryve }); 205fa3d789dSPierre van Houtryve } 206fa3d789dSPierre van Houtryve 207fa3d789dSPierre van Houtryve //===- InstructionOperand -------------------------------------------------===// 208fa3d789dSPierre van Houtryve 209fa3d789dSPierre van Houtryve std::string InstructionOperand::describe() const { 210fa3d789dSPierre van Houtryve if (!hasImmValue()) 211fa3d789dSPierre van Houtryve return "MachineOperand $" + getOperandName().str() + ""; 212fa3d789dSPierre van Houtryve std::string Str = "imm " + std::to_string(getImmValue()); 213fa3d789dSPierre van Houtryve if (isNamedImmediate()) 214fa3d789dSPierre van Houtryve Str += ":$" + getOperandName().str() + ""; 215fa3d789dSPierre van Houtryve return Str; 216fa3d789dSPierre van Houtryve } 217fa3d789dSPierre van Houtryve 218fa3d789dSPierre van Houtryve void InstructionOperand::print(raw_ostream &OS) const { 219fa3d789dSPierre van Houtryve if (isDef()) 220fa3d789dSPierre van Houtryve OS << "<def>"; 221fa3d789dSPierre van Houtryve 222fa3d789dSPierre van Houtryve bool NeedsColon = true; 223fa3d789dSPierre van Houtryve if (Type) { 224fa3d789dSPierre van Houtryve if (hasImmValue()) 225fa3d789dSPierre van Houtryve OS << "(" << Type.str() << " " << getImmValue() << ")"; 226fa3d789dSPierre van Houtryve else 227fa3d789dSPierre van Houtryve OS << Type.str(); 228fa3d789dSPierre van Houtryve } else if (hasImmValue()) 229fa3d789dSPierre van Houtryve OS << getImmValue(); 230fa3d789dSPierre van Houtryve else 231fa3d789dSPierre van Houtryve NeedsColon = false; 232fa3d789dSPierre van Houtryve 233fa3d789dSPierre van Houtryve if (isNamedOperand()) 234fa3d789dSPierre van Houtryve OS << (NeedsColon ? ":" : "") << "$" << getOperandName(); 235fa3d789dSPierre van Houtryve } 236fa3d789dSPierre van Houtryve 237fa3d789dSPierre van Houtryve void InstructionOperand::dump() const { return print(dbgs()); } 238fa3d789dSPierre van Houtryve 239fa3d789dSPierre van Houtryve //===- InstructionPattern -------------------------------------------------===// 240fa3d789dSPierre van Houtryve 241fa3d789dSPierre van Houtryve bool InstructionPattern::diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc, 242fa3d789dSPierre van Houtryve Twine Msg) const { 243fa3d789dSPierre van Houtryve bool HasDiag = false; 244fa3d789dSPierre van Houtryve for (const auto &[Idx, Op] : enumerate(operands())) { 245fa3d789dSPierre van Houtryve if (Op.getType().isSpecial()) { 246fa3d789dSPierre van Houtryve PrintError(Loc, Msg); 247fa3d789dSPierre van Houtryve PrintNote(Loc, "operand " + Twine(Idx) + " of '" + getName() + 248fa3d789dSPierre van Houtryve "' has type '" + Op.getType().str() + "'"); 249fa3d789dSPierre van Houtryve HasDiag = true; 250fa3d789dSPierre van Houtryve } 251fa3d789dSPierre van Houtryve } 252fa3d789dSPierre van Houtryve return HasDiag; 253fa3d789dSPierre van Houtryve } 254fa3d789dSPierre van Houtryve 255fa3d789dSPierre van Houtryve void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const { 256fa3d789dSPierre van Houtryve PrintError(Locs, "pattern '" + getName() + "' ('" + getInstName() + 257fa3d789dSPierre van Houtryve "') is unreachable from the pattern root!"); 258fa3d789dSPierre van Houtryve } 259fa3d789dSPierre van Houtryve 260fa3d789dSPierre van Houtryve bool InstructionPattern::checkSemantics(ArrayRef<SMLoc> Loc) { 261fa3d789dSPierre van Houtryve unsigned NumExpectedOperands = getNumInstOperands(); 262fa3d789dSPierre van Houtryve 263fa3d789dSPierre van Houtryve if (isVariadic()) { 264fa3d789dSPierre van Houtryve if (Operands.size() < NumExpectedOperands) { 265fa3d789dSPierre van Houtryve PrintError(Loc, +"'" + getInstName() + "' expected at least " + 266fa3d789dSPierre van Houtryve Twine(NumExpectedOperands) + " operands, got " + 267fa3d789dSPierre van Houtryve Twine(Operands.size())); 268fa3d789dSPierre van Houtryve return false; 269fa3d789dSPierre van Houtryve } 270fa3d789dSPierre van Houtryve } else if (NumExpectedOperands != Operands.size()) { 271fa3d789dSPierre van Houtryve PrintError(Loc, +"'" + getInstName() + "' expected " + 272fa3d789dSPierre van Houtryve Twine(NumExpectedOperands) + " operands, got " + 273fa3d789dSPierre van Houtryve Twine(Operands.size())); 274fa3d789dSPierre van Houtryve return false; 275fa3d789dSPierre van Houtryve } 276fa3d789dSPierre van Houtryve 277fa3d789dSPierre van Houtryve unsigned OpIdx = 0; 278fa3d789dSPierre van Houtryve unsigned NumDefs = getNumInstDefs(); 279fa3d789dSPierre van Houtryve for (auto &Op : Operands) 280fa3d789dSPierre van Houtryve Op.setIsDef(OpIdx++ < NumDefs); 281fa3d789dSPierre van Houtryve 282fa3d789dSPierre van Houtryve return true; 283fa3d789dSPierre van Houtryve } 284fa3d789dSPierre van Houtryve 285fa3d789dSPierre van Houtryve void InstructionPattern::print(raw_ostream &OS, bool PrintName) const { 286fa3d789dSPierre van Houtryve printImpl(OS, PrintName, [&OS, this] { 287fa3d789dSPierre van Houtryve OS << getInstName() << " operands:["; 288fa3d789dSPierre van Houtryve StringRef Sep; 289fa3d789dSPierre van Houtryve for (const auto &Op : Operands) { 290fa3d789dSPierre van Houtryve OS << Sep; 291fa3d789dSPierre van Houtryve Op.print(OS); 292fa3d789dSPierre van Houtryve Sep = ", "; 293fa3d789dSPierre van Houtryve } 294fa3d789dSPierre van Houtryve OS << "]"; 295fa3d789dSPierre van Houtryve 296fa3d789dSPierre van Houtryve printExtras(OS); 297fa3d789dSPierre van Houtryve }); 298fa3d789dSPierre van Houtryve } 299fa3d789dSPierre van Houtryve 300fa3d789dSPierre van Houtryve //===- OperandTable -------------------------------------------------------===// 301fa3d789dSPierre van Houtryve 302fa3d789dSPierre van Houtryve bool OperandTable::addPattern(InstructionPattern *P, 303fa3d789dSPierre van Houtryve function_ref<void(StringRef)> DiagnoseRedef) { 304fa3d789dSPierre van Houtryve for (const auto &Op : P->named_operands()) { 305fa3d789dSPierre van Houtryve StringRef OpName = Op.getOperandName(); 306fa3d789dSPierre van Houtryve 307fa3d789dSPierre van Houtryve // We always create an entry in the OperandTable, even for uses. 308fa3d789dSPierre van Houtryve // Uses of operands that don't have a def (= live-ins) will remain with a 309fa3d789dSPierre van Houtryve // nullptr as the Def. 310fa3d789dSPierre van Houtryve // 311fa3d789dSPierre van Houtryve // This allows us tell whether an operand exists in a pattern or not. If 312fa3d789dSPierre van Houtryve // there is no entry for it, it doesn't exist, if there is an entry, it's 313fa3d789dSPierre van Houtryve // used/def'd at least once. 314fa3d789dSPierre van Houtryve auto &Def = Table[OpName]; 315fa3d789dSPierre van Houtryve 316fa3d789dSPierre van Houtryve if (!Op.isDef()) 317fa3d789dSPierre van Houtryve continue; 318fa3d789dSPierre van Houtryve 319fa3d789dSPierre van Houtryve if (Def) { 320fa3d789dSPierre van Houtryve DiagnoseRedef(OpName); 321fa3d789dSPierre van Houtryve return false; 322fa3d789dSPierre van Houtryve } 323fa3d789dSPierre van Houtryve 324fa3d789dSPierre van Houtryve Def = P; 325fa3d789dSPierre van Houtryve } 326fa3d789dSPierre van Houtryve 327fa3d789dSPierre van Houtryve return true; 328fa3d789dSPierre van Houtryve } 329fa3d789dSPierre van Houtryve 330fa3d789dSPierre van Houtryve void OperandTable::print(raw_ostream &OS, StringRef Name, 331fa3d789dSPierre van Houtryve StringRef Indent) const { 332fa3d789dSPierre van Houtryve OS << Indent << "(OperandTable "; 333fa3d789dSPierre van Houtryve if (!Name.empty()) 334fa3d789dSPierre van Houtryve OS << Name << " "; 335fa3d789dSPierre van Houtryve if (Table.empty()) { 336fa3d789dSPierre van Houtryve OS << "<empty>)\n"; 337fa3d789dSPierre van Houtryve return; 338fa3d789dSPierre van Houtryve } 339fa3d789dSPierre van Houtryve 340fa3d789dSPierre van Houtryve SmallVector<StringRef, 0> Keys(Table.keys()); 341fa3d789dSPierre van Houtryve sort(Keys); 342fa3d789dSPierre van Houtryve 343fa3d789dSPierre van Houtryve OS << '\n'; 344fa3d789dSPierre van Houtryve for (const auto &Key : Keys) { 345fa3d789dSPierre van Houtryve const auto *Def = Table.at(Key); 346fa3d789dSPierre van Houtryve OS << Indent << " " << Key << " -> " 347fa3d789dSPierre van Houtryve << (Def ? Def->getName() : "<live-in>") << '\n'; 348fa3d789dSPierre van Houtryve } 349fa3d789dSPierre van Houtryve OS << Indent << ")\n"; 350fa3d789dSPierre van Houtryve } 351fa3d789dSPierre van Houtryve 352fa3d789dSPierre van Houtryve void OperandTable::dump() const { print(dbgs()); } 353fa3d789dSPierre van Houtryve 354fa3d789dSPierre van Houtryve //===- MIFlagsInfo --------------------------------------------------------===// 355fa3d789dSPierre van Houtryve 356fa3d789dSPierre van Houtryve void MIFlagsInfo::addSetFlag(const Record *R) { 357fa3d789dSPierre van Houtryve SetF.insert(R->getValueAsString("EnumName")); 358fa3d789dSPierre van Houtryve } 359fa3d789dSPierre van Houtryve 360fa3d789dSPierre van Houtryve void MIFlagsInfo::addUnsetFlag(const Record *R) { 361fa3d789dSPierre van Houtryve UnsetF.insert(R->getValueAsString("EnumName")); 362fa3d789dSPierre van Houtryve } 363fa3d789dSPierre van Houtryve 364fa3d789dSPierre van Houtryve void MIFlagsInfo::addCopyFlag(StringRef InstName) { CopyF.insert(InstName); } 365fa3d789dSPierre van Houtryve 366fa3d789dSPierre van Houtryve //===- CodeGenInstructionPattern ------------------------------------------===// 367fa3d789dSPierre van Houtryve 368fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::is(StringRef OpcodeName) const { 369fa3d789dSPierre van Houtryve return I.TheDef->getName() == OpcodeName; 370fa3d789dSPierre van Houtryve } 371fa3d789dSPierre van Houtryve 372fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::isVariadic() const { 373fa3d789dSPierre van Houtryve return !isIntrinsic() && I.Operands.isVariadic; 374fa3d789dSPierre van Houtryve } 375fa3d789dSPierre van Houtryve 376fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::hasVariadicDefs() const { 377fa3d789dSPierre van Houtryve // Note: we cannot use variadicOpsAreDefs, it's not set for 378fa3d789dSPierre van Houtryve // GenericInstructions. 379fa3d789dSPierre van Houtryve if (!isVariadic()) 380fa3d789dSPierre van Houtryve return false; 381fa3d789dSPierre van Houtryve 382fa3d789dSPierre van Houtryve if (I.variadicOpsAreDefs) 383fa3d789dSPierre van Houtryve return true; 384fa3d789dSPierre van Houtryve 385*62e2c7fbSRahul Joshi const DagInit *OutOps = I.TheDef->getValueAsDag("OutOperandList"); 386fa3d789dSPierre van Houtryve if (OutOps->arg_empty()) 387fa3d789dSPierre van Houtryve return false; 388fa3d789dSPierre van Houtryve 389fa3d789dSPierre van Houtryve auto *LastArgTy = dyn_cast<DefInit>(OutOps->getArg(OutOps->arg_size() - 1)); 390fa3d789dSPierre van Houtryve return LastArgTy && LastArgTy->getDef()->getName() == "variable_ops"; 391fa3d789dSPierre van Houtryve } 392fa3d789dSPierre van Houtryve 393fa3d789dSPierre van Houtryve unsigned CodeGenInstructionPattern::getNumInstDefs() const { 394fa3d789dSPierre van Houtryve if (isIntrinsic()) 395fa3d789dSPierre van Houtryve return IntrinInfo->IS.RetTys.size(); 396fa3d789dSPierre van Houtryve 397fa3d789dSPierre van Houtryve if (!isVariadic() || !hasVariadicDefs()) 398fa3d789dSPierre van Houtryve return I.Operands.NumDefs; 399fa3d789dSPierre van Houtryve unsigned NumOuts = I.Operands.size() - I.Operands.NumDefs; 400fa3d789dSPierre van Houtryve assert(Operands.size() > NumOuts); 401fa3d789dSPierre van Houtryve return std::max<unsigned>(I.Operands.NumDefs, Operands.size() - NumOuts); 402fa3d789dSPierre van Houtryve } 403fa3d789dSPierre van Houtryve 404fa3d789dSPierre van Houtryve unsigned CodeGenInstructionPattern::getNumInstOperands() const { 405fa3d789dSPierre van Houtryve if (isIntrinsic()) 406fa3d789dSPierre van Houtryve return IntrinInfo->IS.RetTys.size() + IntrinInfo->IS.ParamTys.size(); 407fa3d789dSPierre van Houtryve 408fa3d789dSPierre van Houtryve unsigned NumCGIOps = I.Operands.size(); 409fa3d789dSPierre van Houtryve return isVariadic() ? std::max<unsigned>(NumCGIOps, Operands.size()) 410fa3d789dSPierre van Houtryve : NumCGIOps; 411fa3d789dSPierre van Houtryve } 412fa3d789dSPierre van Houtryve 413fa3d789dSPierre van Houtryve MIFlagsInfo &CodeGenInstructionPattern::getOrCreateMIFlagsInfo() { 414fa3d789dSPierre van Houtryve if (!FI) 415fa3d789dSPierre van Houtryve FI = std::make_unique<MIFlagsInfo>(); 416fa3d789dSPierre van Houtryve return *FI; 417fa3d789dSPierre van Houtryve } 418fa3d789dSPierre van Houtryve 419fa3d789dSPierre van Houtryve StringRef CodeGenInstructionPattern::getInstName() const { 420fa3d789dSPierre van Houtryve return I.TheDef->getName(); 421fa3d789dSPierre van Houtryve } 422fa3d789dSPierre van Houtryve 423fa3d789dSPierre van Houtryve void CodeGenInstructionPattern::printExtras(raw_ostream &OS) const { 424fa3d789dSPierre van Houtryve if (isIntrinsic()) 425fa3d789dSPierre van Houtryve OS << " intrinsic(@" << IntrinInfo->Name << ")"; 426fa3d789dSPierre van Houtryve 427fa3d789dSPierre van Houtryve if (!FI) 428fa3d789dSPierre van Houtryve return; 429fa3d789dSPierre van Houtryve 430fa3d789dSPierre van Houtryve OS << " (MIFlags"; 431fa3d789dSPierre van Houtryve if (!FI->set_flags().empty()) 432fa3d789dSPierre van Houtryve OS << " (set " << join(FI->set_flags(), ", ") << ")"; 433fa3d789dSPierre van Houtryve if (!FI->unset_flags().empty()) 434fa3d789dSPierre van Houtryve OS << " (unset " << join(FI->unset_flags(), ", ") << ")"; 435fa3d789dSPierre van Houtryve if (!FI->copy_flags().empty()) 436fa3d789dSPierre van Houtryve OS << " (copy " << join(FI->copy_flags(), ", ") << ")"; 437fa3d789dSPierre van Houtryve OS << ')'; 438fa3d789dSPierre van Houtryve } 439fa3d789dSPierre van Houtryve 440fa3d789dSPierre van Houtryve //===- OperandTypeChecker -------------------------------------------------===// 441fa3d789dSPierre van Houtryve 442fa3d789dSPierre van Houtryve bool OperandTypeChecker::check( 443fa3d789dSPierre van Houtryve InstructionPattern &P, 444fa3d789dSPierre van Houtryve std::function<bool(const PatternType &)> VerifyTypeOfOperand) { 445fa3d789dSPierre van Houtryve Pats.push_back(&P); 446fa3d789dSPierre van Houtryve 447fa3d789dSPierre van Houtryve for (auto &Op : P.operands()) { 448fa3d789dSPierre van Houtryve const auto Ty = Op.getType(); 449fa3d789dSPierre van Houtryve if (!Ty) 450fa3d789dSPierre van Houtryve continue; 451fa3d789dSPierre van Houtryve 452fa3d789dSPierre van Houtryve if (Ty.isTypeOf() && !VerifyTypeOfOperand(Ty)) 453fa3d789dSPierre van Houtryve return false; 454fa3d789dSPierre van Houtryve 455fa3d789dSPierre van Houtryve if (!Op.isNamedOperand()) 456fa3d789dSPierre van Houtryve continue; 457fa3d789dSPierre van Houtryve 458fa3d789dSPierre van Houtryve StringRef OpName = Op.getOperandName(); 459fa3d789dSPierre van Houtryve auto &Info = Types[OpName]; 460fa3d789dSPierre van Houtryve if (!Info.Type) { 461fa3d789dSPierre van Houtryve Info.Type = Ty; 462fa3d789dSPierre van Houtryve Info.PrintTypeSrcNote = [this, OpName, Ty, &P]() { 463fa3d789dSPierre van Houtryve PrintSeenWithTypeIn(P, OpName, Ty); 464fa3d789dSPierre van Houtryve }; 465fa3d789dSPierre van Houtryve continue; 466fa3d789dSPierre van Houtryve } 467fa3d789dSPierre van Houtryve 468fa3d789dSPierre van Houtryve if (Info.Type != Ty) { 469fa3d789dSPierre van Houtryve PrintError(DiagLoc, "conflicting types for operand '" + 470fa3d789dSPierre van Houtryve Op.getOperandName() + "': '" + Info.Type.str() + 471fa3d789dSPierre van Houtryve "' vs '" + Ty.str() + "'"); 472fa3d789dSPierre van Houtryve PrintSeenWithTypeIn(P, OpName, Ty); 473fa3d789dSPierre van Houtryve Info.PrintTypeSrcNote(); 474fa3d789dSPierre van Houtryve return false; 475fa3d789dSPierre van Houtryve } 476fa3d789dSPierre van Houtryve } 477fa3d789dSPierre van Houtryve 478fa3d789dSPierre van Houtryve return true; 479fa3d789dSPierre van Houtryve } 480fa3d789dSPierre van Houtryve 481fa3d789dSPierre van Houtryve void OperandTypeChecker::propagateTypes() { 482fa3d789dSPierre van Houtryve for (auto *Pat : Pats) { 483fa3d789dSPierre van Houtryve for (auto &Op : Pat->named_operands()) { 484fa3d789dSPierre van Houtryve if (auto &Info = Types[Op.getOperandName()]; Info.Type) 485fa3d789dSPierre van Houtryve Op.setType(Info.Type); 486fa3d789dSPierre van Houtryve } 487fa3d789dSPierre van Houtryve } 488fa3d789dSPierre van Houtryve } 489fa3d789dSPierre van Houtryve 490fa3d789dSPierre van Houtryve void OperandTypeChecker::PrintSeenWithTypeIn(InstructionPattern &P, 491fa3d789dSPierre van Houtryve StringRef OpName, 492fa3d789dSPierre van Houtryve PatternType Ty) const { 493fa3d789dSPierre van Houtryve PrintNote(DiagLoc, "'" + OpName + "' seen with type '" + Ty.str() + "' in '" + 494fa3d789dSPierre van Houtryve P.getName() + "'"); 495fa3d789dSPierre van Houtryve } 496fa3d789dSPierre van Houtryve 497fa3d789dSPierre van Houtryve StringRef PatFrag::getParamKindStr(ParamKind OK) { 498fa3d789dSPierre van Houtryve switch (OK) { 499fa3d789dSPierre van Houtryve case PK_Root: 500fa3d789dSPierre van Houtryve return "root"; 501fa3d789dSPierre van Houtryve case PK_MachineOperand: 502fa3d789dSPierre van Houtryve return "machine_operand"; 503fa3d789dSPierre van Houtryve case PK_Imm: 504fa3d789dSPierre van Houtryve return "imm"; 505fa3d789dSPierre van Houtryve } 506fa3d789dSPierre van Houtryve 507fa3d789dSPierre van Houtryve llvm_unreachable("Unknown operand kind!"); 508fa3d789dSPierre van Houtryve } 509fa3d789dSPierre van Houtryve 510fa3d789dSPierre van Houtryve //===- PatFrag -----------------------------------------------------------===// 511fa3d789dSPierre van Houtryve 512fa3d789dSPierre van Houtryve PatFrag::PatFrag(const Record &Def) : Def(Def) { 513fa3d789dSPierre van Houtryve assert(Def.isSubClassOf(ClassName)); 514fa3d789dSPierre van Houtryve } 515fa3d789dSPierre van Houtryve 516fa3d789dSPierre van Houtryve StringRef PatFrag::getName() const { return Def.getName(); } 517fa3d789dSPierre van Houtryve 518fa3d789dSPierre van Houtryve ArrayRef<SMLoc> PatFrag::getLoc() const { return Def.getLoc(); } 519fa3d789dSPierre van Houtryve 520fa3d789dSPierre van Houtryve void PatFrag::addInParam(StringRef Name, ParamKind Kind) { 521fa3d789dSPierre van Houtryve Params.emplace_back(Param{Name, Kind}); 522fa3d789dSPierre van Houtryve } 523fa3d789dSPierre van Houtryve 524fa3d789dSPierre van Houtryve iterator_range<PatFrag::ParamIt> PatFrag::in_params() const { 525fa3d789dSPierre van Houtryve return {Params.begin() + NumOutParams, Params.end()}; 526fa3d789dSPierre van Houtryve } 527fa3d789dSPierre van Houtryve 528fa3d789dSPierre van Houtryve void PatFrag::addOutParam(StringRef Name, ParamKind Kind) { 529fa3d789dSPierre van Houtryve assert(NumOutParams == Params.size() && 530fa3d789dSPierre van Houtryve "Adding out-param after an in-param!"); 531fa3d789dSPierre van Houtryve Params.emplace_back(Param{Name, Kind}); 532fa3d789dSPierre van Houtryve ++NumOutParams; 533fa3d789dSPierre van Houtryve } 534fa3d789dSPierre van Houtryve 535fa3d789dSPierre van Houtryve iterator_range<PatFrag::ParamIt> PatFrag::out_params() const { 536fa3d789dSPierre van Houtryve return {Params.begin(), Params.begin() + NumOutParams}; 537fa3d789dSPierre van Houtryve } 538fa3d789dSPierre van Houtryve 539fa3d789dSPierre van Houtryve unsigned PatFrag::num_roots() const { 540fa3d789dSPierre van Houtryve return count_if(out_params(), 541fa3d789dSPierre van Houtryve [&](const auto &P) { return P.Kind == PK_Root; }); 542fa3d789dSPierre van Houtryve } 543fa3d789dSPierre van Houtryve 544fa3d789dSPierre van Houtryve unsigned PatFrag::getParamIdx(StringRef Name) const { 545fa3d789dSPierre van Houtryve for (const auto &[Idx, Op] : enumerate(Params)) { 546fa3d789dSPierre van Houtryve if (Op.Name == Name) 547fa3d789dSPierre van Houtryve return Idx; 548fa3d789dSPierre van Houtryve } 549fa3d789dSPierre van Houtryve 550fa3d789dSPierre van Houtryve return -1; 551fa3d789dSPierre van Houtryve } 552fa3d789dSPierre van Houtryve 553fa3d789dSPierre van Houtryve bool PatFrag::checkSemantics() { 554fa3d789dSPierre van Houtryve for (const auto &Alt : Alts) { 555fa3d789dSPierre van Houtryve for (const auto &Pat : Alt.Pats) { 556fa3d789dSPierre van Houtryve switch (Pat->getKind()) { 557fa3d789dSPierre van Houtryve case Pattern::K_AnyOpcode: 558fa3d789dSPierre van Houtryve PrintError("wip_match_opcode cannot be used in " + ClassName); 559fa3d789dSPierre van Houtryve return false; 560fa3d789dSPierre van Houtryve case Pattern::K_Builtin: 561fa3d789dSPierre van Houtryve PrintError("Builtin instructions cannot be used in " + ClassName); 562fa3d789dSPierre van Houtryve return false; 563fa3d789dSPierre van Houtryve case Pattern::K_CXX: 564fa3d789dSPierre van Houtryve continue; 565fa3d789dSPierre van Houtryve case Pattern::K_CodeGenInstruction: 566972c0292SPierre van Houtryve // TODO: Allow VarArgs? 567fa3d789dSPierre van Houtryve if (cast<CodeGenInstructionPattern>(Pat.get())->diagnoseAllSpecialTypes( 568fa3d789dSPierre van Houtryve Def.getLoc(), PatternType::SpecialTyClassName + 569fa3d789dSPierre van Houtryve " is not supported in " + ClassName)) 570fa3d789dSPierre van Houtryve return false; 571fa3d789dSPierre van Houtryve continue; 572fa3d789dSPierre van Houtryve case Pattern::K_PatFrag: 573fa3d789dSPierre van Houtryve // TODO: It's just that the emitter doesn't handle it but technically 574fa3d789dSPierre van Houtryve // there is no reason why we can't. We just have to be careful with 575fa3d789dSPierre van Houtryve // operand mappings, it could get complex. 576fa3d789dSPierre van Houtryve PrintError("nested " + ClassName + " are not supported"); 577fa3d789dSPierre van Houtryve return false; 578fa3d789dSPierre van Houtryve } 579fa3d789dSPierre van Houtryve } 580fa3d789dSPierre van Houtryve } 581fa3d789dSPierre van Houtryve 582fa3d789dSPierre van Houtryve StringSet<> SeenOps; 583fa3d789dSPierre van Houtryve for (const auto &Op : in_params()) { 584fa3d789dSPierre van Houtryve if (SeenOps.count(Op.Name)) { 585fa3d789dSPierre van Houtryve PrintError("duplicate parameter '" + Op.Name + "'"); 586fa3d789dSPierre van Houtryve return false; 587fa3d789dSPierre van Houtryve } 588fa3d789dSPierre van Houtryve 589fa3d789dSPierre van Houtryve // Check this operand is NOT defined in any alternative's patterns. 590fa3d789dSPierre van Houtryve for (const auto &Alt : Alts) { 591fa3d789dSPierre van Houtryve if (Alt.OpTable.lookup(Op.Name).Def) { 592fa3d789dSPierre van Houtryve PrintError("input parameter '" + Op.Name + "' cannot be redefined!"); 593fa3d789dSPierre van Houtryve return false; 594fa3d789dSPierre van Houtryve } 595fa3d789dSPierre van Houtryve } 596fa3d789dSPierre van Houtryve 597fa3d789dSPierre van Houtryve if (Op.Kind == PK_Root) { 598fa3d789dSPierre van Houtryve PrintError("input parameterr '" + Op.Name + "' cannot be a root!"); 599fa3d789dSPierre van Houtryve return false; 600fa3d789dSPierre van Houtryve } 601fa3d789dSPierre van Houtryve 602fa3d789dSPierre van Houtryve SeenOps.insert(Op.Name); 603fa3d789dSPierre van Houtryve } 604fa3d789dSPierre van Houtryve 605fa3d789dSPierre van Houtryve for (const auto &Op : out_params()) { 606fa3d789dSPierre van Houtryve if (Op.Kind != PK_Root && Op.Kind != PK_MachineOperand) { 607fa3d789dSPierre van Houtryve PrintError("output parameter '" + Op.Name + 608fa3d789dSPierre van Houtryve "' must be 'root' or 'gi_mo'"); 609fa3d789dSPierre van Houtryve return false; 610fa3d789dSPierre van Houtryve } 611fa3d789dSPierre van Houtryve 612fa3d789dSPierre van Houtryve if (SeenOps.count(Op.Name)) { 613fa3d789dSPierre van Houtryve PrintError("duplicate parameter '" + Op.Name + "'"); 614fa3d789dSPierre van Houtryve return false; 615fa3d789dSPierre van Houtryve } 616fa3d789dSPierre van Houtryve 617fa3d789dSPierre van Houtryve // Check this operand is defined in all alternative's patterns. 618fa3d789dSPierre van Houtryve for (const auto &Alt : Alts) { 619fa3d789dSPierre van Houtryve const auto *OpDef = Alt.OpTable.getDef(Op.Name); 620fa3d789dSPierre van Houtryve if (!OpDef) { 621fa3d789dSPierre van Houtryve PrintError("output parameter '" + Op.Name + 622fa3d789dSPierre van Houtryve "' must be defined by all alternative patterns in '" + 623fa3d789dSPierre van Houtryve Def.getName() + "'"); 624fa3d789dSPierre van Houtryve return false; 625fa3d789dSPierre van Houtryve } 626fa3d789dSPierre van Houtryve 627fa3d789dSPierre van Houtryve if (Op.Kind == PK_Root && OpDef->getNumInstDefs() != 1) { 628fa3d789dSPierre van Houtryve // The instruction that defines the root must have a single def. 629fa3d789dSPierre van Houtryve // Otherwise we'd need to support multiple roots and it gets messy. 630fa3d789dSPierre van Houtryve // 631fa3d789dSPierre van Houtryve // e.g. this is not supported: 632fa3d789dSPierre van Houtryve // (pattern (G_UNMERGE_VALUES $x, $root, $vec)) 633fa3d789dSPierre van Houtryve PrintError("all instructions that define root '" + Op.Name + "' in '" + 634fa3d789dSPierre van Houtryve Def.getName() + "' can only have a single output operand"); 635fa3d789dSPierre van Houtryve return false; 636fa3d789dSPierre van Houtryve } 637fa3d789dSPierre van Houtryve } 638fa3d789dSPierre van Houtryve 639fa3d789dSPierre van Houtryve SeenOps.insert(Op.Name); 640fa3d789dSPierre van Houtryve } 641fa3d789dSPierre van Houtryve 642fa3d789dSPierre van Houtryve if (num_out_params() != 0 && num_roots() == 0) { 643fa3d789dSPierre van Houtryve PrintError(ClassName + " must have one root in its 'out' operands"); 644fa3d789dSPierre van Houtryve return false; 645fa3d789dSPierre van Houtryve } 646fa3d789dSPierre van Houtryve 647fa3d789dSPierre van Houtryve if (num_roots() > 1) { 648fa3d789dSPierre van Houtryve PrintError(ClassName + " can only have one root"); 649fa3d789dSPierre van Houtryve return false; 650fa3d789dSPierre van Houtryve } 651fa3d789dSPierre van Houtryve 652fa3d789dSPierre van Houtryve // TODO: find unused params 653fa3d789dSPierre van Houtryve 654fa3d789dSPierre van Houtryve const auto CheckTypeOf = [&](const PatternType &) -> bool { 655fa3d789dSPierre van Houtryve llvm_unreachable("GITypeOf should have been rejected earlier!"); 656fa3d789dSPierre van Houtryve }; 657fa3d789dSPierre van Houtryve 658fa3d789dSPierre van Houtryve // Now, typecheck all alternatives. 659fa3d789dSPierre van Houtryve for (auto &Alt : Alts) { 660fa3d789dSPierre van Houtryve OperandTypeChecker OTC(Def.getLoc()); 661fa3d789dSPierre van Houtryve for (auto &Pat : Alt.Pats) { 662fa3d789dSPierre van Houtryve if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) { 663fa3d789dSPierre van Houtryve if (!OTC.check(*IP, CheckTypeOf)) 664fa3d789dSPierre van Houtryve return false; 665fa3d789dSPierre van Houtryve } 666fa3d789dSPierre van Houtryve } 667fa3d789dSPierre van Houtryve OTC.propagateTypes(); 668fa3d789dSPierre van Houtryve } 669fa3d789dSPierre van Houtryve 670fa3d789dSPierre van Houtryve return true; 671fa3d789dSPierre van Houtryve } 672fa3d789dSPierre van Houtryve 673fa3d789dSPierre van Houtryve bool PatFrag::handleUnboundInParam(StringRef ParamName, StringRef ArgName, 674fa3d789dSPierre van Houtryve ArrayRef<SMLoc> DiagLoc) const { 675fa3d789dSPierre van Houtryve // The parameter must be a live-in of all alternatives for this to work. 676fa3d789dSPierre van Houtryve // Otherwise, we risk having unbound parameters being used (= crashes). 677fa3d789dSPierre van Houtryve // 678fa3d789dSPierre van Houtryve // Examples: 679fa3d789dSPierre van Houtryve // 680fa3d789dSPierre van Houtryve // in (ins $y), (patterns (G_FNEG $dst, $y), "return matchFnegOp(${y})") 681fa3d789dSPierre van Houtryve // even if $y is unbound, we'll lazily bind it when emitting the G_FNEG. 682fa3d789dSPierre van Houtryve // 683fa3d789dSPierre van Houtryve // in (ins $y), (patterns "return matchFnegOp(${y})") 684fa3d789dSPierre van Houtryve // if $y is unbound when this fragment is emitted, C++ code expansion will 685fa3d789dSPierre van Houtryve // fail. 686fa3d789dSPierre van Houtryve for (const auto &Alt : Alts) { 687fa3d789dSPierre van Houtryve auto &OT = Alt.OpTable; 688fa3d789dSPierre van Houtryve if (!OT.lookup(ParamName).Found) { 689fa3d789dSPierre van Houtryve llvm::PrintError(DiagLoc, "operand '" + ArgName + "' (for parameter '" + 690fa3d789dSPierre van Houtryve ParamName + "' of '" + getName() + 691fa3d789dSPierre van Houtryve "') cannot be unbound"); 692fa3d789dSPierre van Houtryve PrintNote( 693fa3d789dSPierre van Houtryve DiagLoc, 694fa3d789dSPierre van Houtryve "one or more alternatives of '" + getName() + "' do not bind '" + 695fa3d789dSPierre van Houtryve ParamName + 696fa3d789dSPierre van Houtryve "' to an instruction operand; either use a bound operand or " 697fa3d789dSPierre van Houtryve "ensure '" + 698fa3d789dSPierre van Houtryve Def.getName() + "' binds '" + ParamName + 699fa3d789dSPierre van Houtryve "' in all alternatives"); 700fa3d789dSPierre van Houtryve return false; 701fa3d789dSPierre van Houtryve } 702fa3d789dSPierre van Houtryve } 703fa3d789dSPierre van Houtryve 704fa3d789dSPierre van Houtryve return true; 705fa3d789dSPierre van Houtryve } 706fa3d789dSPierre van Houtryve 707fa3d789dSPierre van Houtryve bool PatFrag::buildOperandsTables() { 708fa3d789dSPierre van Houtryve // enumerate(...) doesn't seem to allow lvalues so we need to count the old 709fa3d789dSPierre van Houtryve // way. 710fa3d789dSPierre van Houtryve unsigned Idx = 0; 711fa3d789dSPierre van Houtryve 712fa3d789dSPierre van Houtryve const auto DiagnoseRedef = [this, &Idx](StringRef OpName) { 713fa3d789dSPierre van Houtryve PrintError("Operand '" + OpName + 714fa3d789dSPierre van Houtryve "' is defined multiple times in patterns of alternative #" + 715fa3d789dSPierre van Houtryve std::to_string(Idx)); 716fa3d789dSPierre van Houtryve }; 717fa3d789dSPierre van Houtryve 718fa3d789dSPierre van Houtryve for (auto &Alt : Alts) { 719fa3d789dSPierre van Houtryve for (auto &Pat : Alt.Pats) { 720fa3d789dSPierre van Houtryve auto *IP = dyn_cast<InstructionPattern>(Pat.get()); 721fa3d789dSPierre van Houtryve if (!IP) 722fa3d789dSPierre van Houtryve continue; 723fa3d789dSPierre van Houtryve 724fa3d789dSPierre van Houtryve if (!Alt.OpTable.addPattern(IP, DiagnoseRedef)) 725fa3d789dSPierre van Houtryve return false; 726fa3d789dSPierre van Houtryve } 727fa3d789dSPierre van Houtryve 728fa3d789dSPierre van Houtryve ++Idx; 729fa3d789dSPierre van Houtryve } 730fa3d789dSPierre van Houtryve 731fa3d789dSPierre van Houtryve return true; 732fa3d789dSPierre van Houtryve } 733fa3d789dSPierre van Houtryve 734fa3d789dSPierre van Houtryve void PatFrag::print(raw_ostream &OS, StringRef Indent) const { 735fa3d789dSPierre van Houtryve OS << Indent << "(PatFrag name:" << getName() << '\n'; 736fa3d789dSPierre van Houtryve if (!in_params().empty()) { 737fa3d789dSPierre van Houtryve OS << Indent << " (ins "; 738fa3d789dSPierre van Houtryve printParamsList(OS, in_params()); 739fa3d789dSPierre van Houtryve OS << ")\n"; 740fa3d789dSPierre van Houtryve } 741fa3d789dSPierre van Houtryve 742fa3d789dSPierre van Houtryve if (!out_params().empty()) { 743fa3d789dSPierre van Houtryve OS << Indent << " (outs "; 744fa3d789dSPierre van Houtryve printParamsList(OS, out_params()); 745fa3d789dSPierre van Houtryve OS << ")\n"; 746fa3d789dSPierre van Houtryve } 747fa3d789dSPierre van Houtryve 748fa3d789dSPierre van Houtryve // TODO: Dump OperandTable as well. 749fa3d789dSPierre van Houtryve OS << Indent << " (alternatives [\n"; 750fa3d789dSPierre van Houtryve for (const auto &Alt : Alts) { 751fa3d789dSPierre van Houtryve OS << Indent << " [\n"; 752fa3d789dSPierre van Houtryve for (const auto &Pat : Alt.Pats) { 753fa3d789dSPierre van Houtryve OS << Indent << " "; 754fa3d789dSPierre van Houtryve Pat->print(OS, /*PrintName=*/true); 755fa3d789dSPierre van Houtryve OS << ",\n"; 756fa3d789dSPierre van Houtryve } 757fa3d789dSPierre van Houtryve OS << Indent << " ],\n"; 758fa3d789dSPierre van Houtryve } 759fa3d789dSPierre van Houtryve OS << Indent << " ])\n"; 760fa3d789dSPierre van Houtryve 761fa3d789dSPierre van Houtryve OS << Indent << ')'; 762fa3d789dSPierre van Houtryve } 763fa3d789dSPierre van Houtryve 764fa3d789dSPierre van Houtryve void PatFrag::dump() const { print(dbgs()); } 765fa3d789dSPierre van Houtryve 766fa3d789dSPierre van Houtryve void PatFrag::printParamsList(raw_ostream &OS, iterator_range<ParamIt> Params) { 767fa3d789dSPierre van Houtryve OS << '[' 768fa3d789dSPierre van Houtryve << join(map_range(Params, 769fa3d789dSPierre van Houtryve [](auto &O) { 770fa3d789dSPierre van Houtryve return (O.Name + ":" + getParamKindStr(O.Kind)).str(); 771fa3d789dSPierre van Houtryve }), 772fa3d789dSPierre van Houtryve ", ") 773fa3d789dSPierre van Houtryve << ']'; 774fa3d789dSPierre van Houtryve } 775fa3d789dSPierre van Houtryve 776fa3d789dSPierre van Houtryve void PatFrag::PrintError(Twine Msg) const { llvm::PrintError(&Def, Msg); } 777fa3d789dSPierre van Houtryve 778fa3d789dSPierre van Houtryve ArrayRef<InstructionOperand> PatFragPattern::getApplyDefsNeeded() const { 779fa3d789dSPierre van Houtryve assert(PF.num_roots() == 1); 780fa3d789dSPierre van Houtryve // Only roots need to be redef. 781fa3d789dSPierre van Houtryve for (auto [Idx, Param] : enumerate(PF.out_params())) { 782fa3d789dSPierre van Houtryve if (Param.Kind == PatFrag::PK_Root) 783fa3d789dSPierre van Houtryve return getOperand(Idx); 784fa3d789dSPierre van Houtryve } 785fa3d789dSPierre van Houtryve llvm_unreachable("root not found!"); 786fa3d789dSPierre van Houtryve } 787fa3d789dSPierre van Houtryve 788fa3d789dSPierre van Houtryve //===- PatFragPattern -----------------------------------------------------===// 789fa3d789dSPierre van Houtryve 790fa3d789dSPierre van Houtryve bool PatFragPattern::checkSemantics(ArrayRef<SMLoc> DiagLoc) { 791fa3d789dSPierre van Houtryve if (!InstructionPattern::checkSemantics(DiagLoc)) 792fa3d789dSPierre van Houtryve return false; 793fa3d789dSPierre van Houtryve 794fa3d789dSPierre van Houtryve for (const auto &[Idx, Op] : enumerate(Operands)) { 795fa3d789dSPierre van Houtryve switch (PF.getParam(Idx).Kind) { 796fa3d789dSPierre van Houtryve case PatFrag::PK_Imm: 797fa3d789dSPierre van Houtryve if (!Op.hasImmValue()) { 798fa3d789dSPierre van Houtryve PrintError(DiagLoc, "expected operand " + std::to_string(Idx) + 799fa3d789dSPierre van Houtryve " of '" + getInstName() + 800fa3d789dSPierre van Houtryve "' to be an immediate; got " + Op.describe()); 801fa3d789dSPierre van Houtryve return false; 802fa3d789dSPierre van Houtryve } 803fa3d789dSPierre van Houtryve if (Op.isNamedImmediate()) { 804fa3d789dSPierre van Houtryve PrintError(DiagLoc, "operand " + std::to_string(Idx) + " of '" + 805fa3d789dSPierre van Houtryve getInstName() + 806fa3d789dSPierre van Houtryve "' cannot be a named immediate"); 807fa3d789dSPierre van Houtryve return false; 808fa3d789dSPierre van Houtryve } 809fa3d789dSPierre van Houtryve break; 810fa3d789dSPierre van Houtryve case PatFrag::PK_Root: 811fa3d789dSPierre van Houtryve case PatFrag::PK_MachineOperand: 812fa3d789dSPierre van Houtryve if (!Op.isNamedOperand() || Op.isNamedImmediate()) { 813fa3d789dSPierre van Houtryve PrintError(DiagLoc, "expected operand " + std::to_string(Idx) + 814fa3d789dSPierre van Houtryve " of '" + getInstName() + 815fa3d789dSPierre van Houtryve "' to be a MachineOperand; got " + 816fa3d789dSPierre van Houtryve Op.describe()); 817fa3d789dSPierre van Houtryve return false; 818fa3d789dSPierre van Houtryve } 819fa3d789dSPierre van Houtryve break; 820fa3d789dSPierre van Houtryve } 821fa3d789dSPierre van Houtryve } 822fa3d789dSPierre van Houtryve 823fa3d789dSPierre van Houtryve return true; 824fa3d789dSPierre van Houtryve } 825fa3d789dSPierre van Houtryve 826fa3d789dSPierre van Houtryve bool PatFragPattern::mapInputCodeExpansions(const CodeExpansions &ParentCEs, 827fa3d789dSPierre van Houtryve CodeExpansions &PatFragCEs, 828fa3d789dSPierre van Houtryve ArrayRef<SMLoc> DiagLoc) const { 829fa3d789dSPierre van Houtryve for (const auto &[Idx, Op] : enumerate(operands())) { 830fa3d789dSPierre van Houtryve StringRef ParamName = PF.getParam(Idx).Name; 831fa3d789dSPierre van Houtryve 832fa3d789dSPierre van Houtryve // Operands to a PFP can only be named, or be an immediate, but not a named 833fa3d789dSPierre van Houtryve // immediate. 834fa3d789dSPierre van Houtryve assert(!Op.isNamedImmediate()); 835fa3d789dSPierre van Houtryve 836fa3d789dSPierre van Houtryve if (Op.isNamedOperand()) { 837fa3d789dSPierre van Houtryve StringRef ArgName = Op.getOperandName(); 838fa3d789dSPierre van Houtryve // Map it only if it's been defined. 839fa3d789dSPierre van Houtryve auto It = ParentCEs.find(ArgName); 840fa3d789dSPierre van Houtryve if (It == ParentCEs.end()) { 841fa3d789dSPierre van Houtryve if (!PF.handleUnboundInParam(ParamName, ArgName, DiagLoc)) 842fa3d789dSPierre van Houtryve return false; 843fa3d789dSPierre van Houtryve } else 844fa3d789dSPierre van Houtryve PatFragCEs.declare(ParamName, It->second); 845fa3d789dSPierre van Houtryve continue; 846fa3d789dSPierre van Houtryve } 847fa3d789dSPierre van Houtryve 848fa3d789dSPierre van Houtryve if (Op.hasImmValue()) { 849fa3d789dSPierre van Houtryve PatFragCEs.declare(ParamName, std::to_string(Op.getImmValue())); 850fa3d789dSPierre van Houtryve continue; 851fa3d789dSPierre van Houtryve } 852fa3d789dSPierre van Houtryve 853fa3d789dSPierre van Houtryve llvm_unreachable("Unknown Operand Type!"); 854fa3d789dSPierre van Houtryve } 855fa3d789dSPierre van Houtryve 856fa3d789dSPierre van Houtryve return true; 857fa3d789dSPierre van Houtryve } 858fa3d789dSPierre van Houtryve 859fa3d789dSPierre van Houtryve //===- BuiltinPattern -----------------------------------------------------===// 860fa3d789dSPierre van Houtryve 861fa3d789dSPierre van Houtryve BuiltinPattern::BuiltinInfo BuiltinPattern::getBuiltinInfo(const Record &Def) { 862fa3d789dSPierre van Houtryve assert(Def.isSubClassOf(ClassName)); 863fa3d789dSPierre van Houtryve 864fa3d789dSPierre van Houtryve StringRef Name = Def.getName(); 865fa3d789dSPierre van Houtryve for (const auto &KBI : KnownBuiltins) { 866fa3d789dSPierre van Houtryve if (KBI.DefName == Name) 867fa3d789dSPierre van Houtryve return KBI; 868fa3d789dSPierre van Houtryve } 869fa3d789dSPierre van Houtryve 870fa3d789dSPierre van Houtryve PrintFatalError(Def.getLoc(), 871fa3d789dSPierre van Houtryve "Unimplemented " + ClassName + " def '" + Name + "'"); 872fa3d789dSPierre van Houtryve } 873fa3d789dSPierre van Houtryve 874fa3d789dSPierre van Houtryve bool BuiltinPattern::checkSemantics(ArrayRef<SMLoc> Loc) { 875fa3d789dSPierre van Houtryve if (!InstructionPattern::checkSemantics(Loc)) 876fa3d789dSPierre van Houtryve return false; 877fa3d789dSPierre van Houtryve 878fa3d789dSPierre van Houtryve // For now all builtins just take names, no immediates. 879fa3d789dSPierre van Houtryve for (const auto &[Idx, Op] : enumerate(operands())) { 880fa3d789dSPierre van Houtryve if (!Op.isNamedOperand() || Op.isNamedImmediate()) { 881fa3d789dSPierre van Houtryve PrintError(Loc, "expected operand " + std::to_string(Idx) + " of '" + 882fa3d789dSPierre van Houtryve getInstName() + "' to be a name"); 883fa3d789dSPierre van Houtryve return false; 884fa3d789dSPierre van Houtryve } 885fa3d789dSPierre van Houtryve } 886fa3d789dSPierre van Houtryve 887fa3d789dSPierre van Houtryve return true; 888fa3d789dSPierre van Houtryve } 889fa3d789dSPierre van Houtryve 890fa3d789dSPierre van Houtryve } // namespace gi 891fa3d789dSPierre van Houtryve } // namespace llvm 892