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