| 1 | //===- CodeGenInstruction.cpp - CodeGen Instruction Class Wrapper ---------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file implements the CodeGenInstruction class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "CodeGenInstruction.h" |
| 14 | #include "CodeGenTarget.h" |
| 15 | #include "llvm/ADT/StringExtras.h" |
| 16 | #include "llvm/TableGen/Error.h" |
| 17 | #include "llvm/TableGen/Record.h" |
| 18 | #include <set> |
| 19 | using namespace llvm; |
| 20 | |
| 21 | //===----------------------------------------------------------------------===// |
| 22 | // CGIOperandList Implementation |
| 23 | //===----------------------------------------------------------------------===// |
| 24 | |
| 25 | CGIOperandList::CGIOperandList(const Record *R) : TheDef(R) { |
| 26 | isPredicable = false; |
| 27 | hasOptionalDef = false; |
| 28 | isVariadic = false; |
| 29 | |
| 30 | const DagInit *OutDI = R->getValueAsDag(FieldName: "OutOperandList" ); |
| 31 | |
| 32 | if (const DefInit *Init = dyn_cast<DefInit>(Val: OutDI->getOperator())) { |
| 33 | if (Init->getDef()->getName() != "outs" ) |
| 34 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 35 | Msg: R->getName() + |
| 36 | ": invalid def name for output list: use 'outs'" ); |
| 37 | } else { |
| 38 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 39 | Msg: R->getName() + ": invalid output list: use 'outs'" ); |
| 40 | } |
| 41 | |
| 42 | NumDefs = OutDI->getNumArgs(); |
| 43 | |
| 44 | const DagInit *InDI = R->getValueAsDag(FieldName: "InOperandList" ); |
| 45 | if (const DefInit *Init = dyn_cast<DefInit>(Val: InDI->getOperator())) { |
| 46 | if (Init->getDef()->getName() != "ins" ) |
| 47 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 48 | Msg: R->getName() + |
| 49 | ": invalid def name for input list: use 'ins'" ); |
| 50 | } else { |
| 51 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 52 | Msg: R->getName() + ": invalid input list: use 'ins'" ); |
| 53 | } |
| 54 | |
| 55 | unsigned MIOperandNo = 0; |
| 56 | std::set<std::string> OperandNames; |
| 57 | unsigned e = InDI->getNumArgs() + OutDI->getNumArgs(); |
| 58 | OperandList.reserve(n: e); |
| 59 | bool VariadicOuts = false; |
| 60 | for (unsigned i = 0; i != e; ++i) { |
| 61 | const Init *ArgInit; |
| 62 | StringRef ArgName; |
| 63 | if (i < NumDefs) { |
| 64 | ArgInit = OutDI->getArg(Num: i); |
| 65 | ArgName = OutDI->getArgNameStr(Num: i); |
| 66 | } else { |
| 67 | ArgInit = InDI->getArg(Num: i - NumDefs); |
| 68 | ArgName = InDI->getArgNameStr(Num: i - NumDefs); |
| 69 | } |
| 70 | |
| 71 | const DagInit *SubArgDag = dyn_cast<DagInit>(Val: ArgInit); |
| 72 | if (SubArgDag) |
| 73 | ArgInit = SubArgDag->getOperator(); |
| 74 | |
| 75 | const DefInit *Arg = dyn_cast<DefInit>(Val: ArgInit); |
| 76 | if (!Arg) |
| 77 | PrintFatalError(ErrorLoc: R->getLoc(), Msg: "Illegal operand for the '" + R->getName() + |
| 78 | "' instruction!" ); |
| 79 | |
| 80 | const Record *Rec = Arg->getDef(); |
| 81 | StringRef PrintMethod = "printOperand" ; |
| 82 | StringRef EncoderMethod; |
| 83 | std::string OperandType = "OPERAND_UNKNOWN" ; |
| 84 | std::string OperandNamespace = "MCOI" ; |
| 85 | unsigned NumOps = 1; |
| 86 | const DagInit *MIOpInfo = nullptr; |
| 87 | if (Rec->isSubClassOf(Name: "RegisterOperand" )) { |
| 88 | PrintMethod = Rec->getValueAsString(FieldName: "PrintMethod" ); |
| 89 | OperandType = Rec->getValueAsString(FieldName: "OperandType" ).str(); |
| 90 | OperandNamespace = Rec->getValueAsString(FieldName: "OperandNamespace" ).str(); |
| 91 | EncoderMethod = Rec->getValueAsString(FieldName: "EncoderMethod" ); |
| 92 | } else if (Rec->isSubClassOf(Name: "Operand" )) { |
| 93 | PrintMethod = Rec->getValueAsString(FieldName: "PrintMethod" ); |
| 94 | OperandType = Rec->getValueAsString(FieldName: "OperandType" ).str(); |
| 95 | OperandNamespace = Rec->getValueAsString(FieldName: "OperandNamespace" ).str(); |
| 96 | // If there is an explicit encoder method, use it. |
| 97 | EncoderMethod = Rec->getValueAsString(FieldName: "EncoderMethod" ); |
| 98 | MIOpInfo = Rec->getValueAsDag(FieldName: "MIOperandInfo" ); |
| 99 | |
| 100 | // Verify that MIOpInfo has an 'ops' root value. |
| 101 | if (!isa<DefInit>(Val: MIOpInfo->getOperator()) || |
| 102 | cast<DefInit>(Val: MIOpInfo->getOperator())->getDef()->getName() != "ops" ) |
| 103 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 104 | Msg: "Bad value for MIOperandInfo in operand '" + |
| 105 | Rec->getName() + "'\n" ); |
| 106 | |
| 107 | // If we have MIOpInfo, then we have #operands equal to number of entries |
| 108 | // in MIOperandInfo. |
| 109 | if (unsigned NumArgs = MIOpInfo->getNumArgs()) |
| 110 | NumOps = NumArgs; |
| 111 | |
| 112 | if (Rec->isSubClassOf(Name: "PredicateOp" )) |
| 113 | isPredicable = true; |
| 114 | else if (Rec->isSubClassOf(Name: "OptionalDefOperand" )) |
| 115 | hasOptionalDef = true; |
| 116 | } else if (Rec->getName() == "variable_ops" ) { |
| 117 | if (i < NumDefs) |
| 118 | VariadicOuts = true; |
| 119 | isVariadic = true; |
| 120 | continue; |
| 121 | } else if (Rec->isSubClassOf(Name: "RegisterClass" )) { |
| 122 | OperandType = "OPERAND_REGISTER" ; |
| 123 | } else if (!Rec->isSubClassOf(Name: "PointerLikeRegClass" ) && |
| 124 | !Rec->isSubClassOf(Name: "unknown_class" )) { |
| 125 | PrintFatalError(ErrorLoc: R->getLoc(), Msg: "Unknown operand class '" + Rec->getName() + |
| 126 | "' in '" + R->getName() + |
| 127 | "' instruction!" ); |
| 128 | } |
| 129 | |
| 130 | // Check that the operand has a name and that it's unique. |
| 131 | if (ArgName.empty()) |
| 132 | PrintFatalError(ErrorLoc: R->getLoc(), Msg: "In instruction '" + R->getName() + |
| 133 | "', operand #" + Twine(i) + |
| 134 | " has no name!" ); |
| 135 | if (!OperandNames.insert(x: ArgName.str()).second) |
| 136 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 137 | Msg: "In instruction '" + R->getName() + "', operand #" + |
| 138 | Twine(i) + |
| 139 | " has the same name as a previous operand!" ); |
| 140 | |
| 141 | OperandInfo &OpInfo = OperandList.emplace_back( |
| 142 | args&: Rec, args&: ArgName, args&: PrintMethod, args: OperandNamespace + "::" + OperandType, |
| 143 | args&: MIOperandNo, args&: NumOps, args&: MIOpInfo); |
| 144 | |
| 145 | if (SubArgDag) { |
| 146 | if (SubArgDag->getNumArgs() != NumOps) { |
| 147 | PrintFatalError(ErrorLoc: R->getLoc(), Msg: "In instruction '" + R->getName() + |
| 148 | "', operand #" + Twine(i) + " has " + |
| 149 | Twine(SubArgDag->getNumArgs()) + |
| 150 | " sub-arg names, expected " + |
| 151 | Twine(NumOps) + "." ); |
| 152 | } |
| 153 | |
| 154 | for (unsigned j = 0; j < NumOps; ++j) { |
| 155 | if (!isa<UnsetInit>(Val: SubArgDag->getArg(Num: j))) |
| 156 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 157 | Msg: "In instruction '" + R->getName() + "', operand #" + |
| 158 | Twine(i) + " sub-arg #" + Twine(j) + |
| 159 | " has unexpected operand (expected only $name)." ); |
| 160 | |
| 161 | StringRef SubArgName = SubArgDag->getArgNameStr(Num: j); |
| 162 | if (SubArgName.empty()) |
| 163 | PrintFatalError(ErrorLoc: R->getLoc(), Msg: "In instruction '" + R->getName() + |
| 164 | "', operand #" + Twine(i) + |
| 165 | " has no name!" ); |
| 166 | if (!OperandNames.insert(x: SubArgName.str()).second) |
| 167 | PrintFatalError(ErrorLoc: R->getLoc(), |
| 168 | Msg: "In instruction '" + R->getName() + "', operand #" + |
| 169 | Twine(i) + " sub-arg #" + Twine(j) + |
| 170 | " has the same name as a previous operand!" ); |
| 171 | |
| 172 | if (auto MaybeEncoderMethod = |
| 173 | cast<DefInit>(Val: MIOpInfo->getArg(Num: j)) |
| 174 | ->getDef() |
| 175 | ->getValueAsOptionalString(FieldName: "EncoderMethod" )) { |
| 176 | OpInfo.EncoderMethodNames[j] = *MaybeEncoderMethod; |
| 177 | } |
| 178 | |
| 179 | OpInfo.SubOpNames[j] = SubArgName; |
| 180 | SubOpAliases[SubArgName] = {i, j}; |
| 181 | } |
| 182 | } else if (!EncoderMethod.empty()) { |
| 183 | // If we have no explicit sub-op dag, but have an top-level encoder |
| 184 | // method, the single encoder will multiple sub-ops, itself. |
| 185 | OpInfo.EncoderMethodNames[0] = EncoderMethod; |
| 186 | OpInfo.DoNotEncode.set(); |
| 187 | OpInfo.DoNotEncode[0] = false; |
| 188 | } |
| 189 | |
| 190 | MIOperandNo += NumOps; |
| 191 | } |
| 192 | |
| 193 | if (VariadicOuts) |
| 194 | --NumDefs; |
| 195 | } |
| 196 | |
| 197 | /// getOperandNamed - Return the index of the operand with the specified |
| 198 | /// non-empty name. If the instruction does not have an operand with the |
| 199 | /// specified name, abort. |
| 200 | /// |
| 201 | unsigned CGIOperandList::getOperandNamed(StringRef Name) const { |
| 202 | std::optional<unsigned> OpIdx = findOperandNamed(Name); |
| 203 | if (OpIdx) |
| 204 | return *OpIdx; |
| 205 | PrintFatalError(ErrorLoc: TheDef->getLoc(), Msg: "'" + TheDef->getName() + |
| 206 | "' does not have an operand named '$" + |
| 207 | Name + "'!" ); |
| 208 | } |
| 209 | |
| 210 | /// findOperandNamed - Query whether the instruction has an operand of the |
| 211 | /// given name. If so, the index of the operand. Otherwise, return std::nullopt. |
| 212 | std::optional<unsigned> CGIOperandList::findOperandNamed(StringRef Name) const { |
| 213 | assert(!Name.empty() && "Cannot search for operand with no name!" ); |
| 214 | for (const auto &[Index, Opnd] : enumerate(First: OperandList)) |
| 215 | if (Opnd.Name == Name) |
| 216 | return Index; |
| 217 | return std::nullopt; |
| 218 | } |
| 219 | |
| 220 | std::optional<std::pair<unsigned, unsigned>> |
| 221 | CGIOperandList::findSubOperandAlias(StringRef Name) const { |
| 222 | assert(!Name.empty() && "Cannot search for operand with no name!" ); |
| 223 | auto SubOpIter = SubOpAliases.find(Key: Name); |
| 224 | if (SubOpIter != SubOpAliases.end()) |
| 225 | return SubOpIter->second; |
| 226 | return std::nullopt; |
| 227 | } |
| 228 | |
| 229 | std::pair<unsigned, unsigned> |
| 230 | CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) { |
| 231 | if (!Op.starts_with(Prefix: "$" )) |
| 232 | PrintFatalError(ErrorLoc: TheDef->getLoc(), |
| 233 | Msg: TheDef->getName() + ": Illegal operand name: '" + Op + "'" ); |
| 234 | |
| 235 | StringRef OpName = Op.substr(Start: 1); |
| 236 | StringRef SubOpName; |
| 237 | |
| 238 | // Check to see if this is $foo.bar. |
| 239 | StringRef::size_type DotIdx = OpName.find_first_of(C: '.'); |
| 240 | if (DotIdx != StringRef::npos) { |
| 241 | SubOpName = OpName.substr(Start: DotIdx + 1); |
| 242 | if (SubOpName.empty()) |
| 243 | PrintFatalError(ErrorLoc: TheDef->getLoc(), |
| 244 | Msg: TheDef->getName() + |
| 245 | ": illegal empty suboperand name in '" + Op + "'" ); |
| 246 | OpName = OpName.substr(Start: 0, N: DotIdx); |
| 247 | } |
| 248 | |
| 249 | if (auto SubOp = findSubOperandAlias(Name: OpName)) { |
| 250 | // Found a name for a piece of an operand, just return it directly. |
| 251 | if (!SubOpName.empty()) { |
| 252 | PrintFatalError( |
| 253 | ErrorLoc: TheDef->getLoc(), |
| 254 | Msg: TheDef->getName() + |
| 255 | ": Cannot use dotted suboperand name within suboperand '" + |
| 256 | OpName + "'" ); |
| 257 | } |
| 258 | return *SubOp; |
| 259 | } |
| 260 | |
| 261 | unsigned OpIdx = getOperandNamed(Name: OpName); |
| 262 | |
| 263 | if (SubOpName.empty()) { // If no suboperand name was specified: |
| 264 | // If one was needed, throw. |
| 265 | if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp && |
| 266 | SubOpName.empty()) |
| 267 | PrintFatalError(ErrorLoc: TheDef->getLoc(), |
| 268 | Msg: TheDef->getName() + |
| 269 | ": Illegal to refer to" |
| 270 | " whole operand part of complex operand '" + |
| 271 | Op + "'" ); |
| 272 | |
| 273 | // Otherwise, return the operand. |
| 274 | return {OpIdx, 0U}; |
| 275 | } |
| 276 | |
| 277 | // Find the suboperand number involved. |
| 278 | const DagInit *MIOpInfo = OperandList[OpIdx].MIOperandInfo; |
| 279 | if (!MIOpInfo) |
| 280 | PrintFatalError(ErrorLoc: TheDef->getLoc(), Msg: TheDef->getName() + |
| 281 | ": unknown suboperand name in '" + |
| 282 | Op + "'" ); |
| 283 | |
| 284 | // Find the operand with the right name. |
| 285 | for (unsigned i = 0, e = MIOpInfo->getNumArgs(); i != e; ++i) |
| 286 | if (MIOpInfo->getArgNameStr(Num: i) == SubOpName) |
| 287 | return {OpIdx, i}; |
| 288 | |
| 289 | // Otherwise, didn't find it! |
| 290 | PrintFatalError(ErrorLoc: TheDef->getLoc(), Msg: TheDef->getName() + |
| 291 | ": unknown suboperand name in '" + Op + |
| 292 | "'" ); |
| 293 | return {0U, 0U}; |
| 294 | } |
| 295 | |
| 296 | static void ParseConstraint(StringRef CStr, CGIOperandList &Ops, |
| 297 | const Record *Rec) { |
| 298 | // EARLY_CLOBBER: @early $reg |
| 299 | StringRef::size_type wpos = CStr.find_first_of(Chars: " \t" ); |
| 300 | StringRef::size_type start = CStr.find_first_not_of(Chars: " \t" ); |
| 301 | StringRef Tok = CStr.substr(Start: start, N: wpos - start); |
| 302 | if (Tok == "@earlyclobber" ) { |
| 303 | StringRef Name = CStr.substr(Start: wpos + 1); |
| 304 | wpos = Name.find_first_not_of(Chars: " \t" ); |
| 305 | if (wpos == StringRef::npos) |
| 306 | PrintFatalError(ErrorLoc: Rec->getLoc(), |
| 307 | Msg: "Illegal format for @earlyclobber constraint in '" + |
| 308 | Rec->getName() + "': '" + CStr + "'" ); |
| 309 | Name = Name.substr(Start: wpos); |
| 310 | std::pair<unsigned, unsigned> Op = Ops.ParseOperandName(Op: Name, AllowWholeOp: false); |
| 311 | |
| 312 | // Build the string for the operand |
| 313 | if (!Ops[Op.first].Constraints[Op.second].isNone()) |
| 314 | PrintFatalError(ErrorLoc: Rec->getLoc(), Msg: "Operand '" + Name + "' of '" + |
| 315 | Rec->getName() + |
| 316 | "' cannot have multiple constraints!" ); |
| 317 | Ops[Op.first].Constraints[Op.second] = |
| 318 | CGIOperandList::ConstraintInfo::getEarlyClobber(); |
| 319 | return; |
| 320 | } |
| 321 | |
| 322 | // Only other constraint is "TIED_TO" for now. |
| 323 | StringRef::size_type pos = CStr.find_first_of(C: '='); |
| 324 | if (pos == StringRef::npos || pos == 0 || |
| 325 | CStr.find_first_of(Chars: " \t" , From: pos) != (pos + 1) || |
| 326 | CStr.find_last_of(Chars: " \t" , From: pos) != (pos - 1)) |
| 327 | PrintFatalError(ErrorLoc: Rec->getLoc(), Msg: "Unrecognized constraint '" + CStr + |
| 328 | "' in '" + Rec->getName() + "'" ); |
| 329 | start = CStr.find_first_not_of(Chars: " \t" ); |
| 330 | |
| 331 | // TIED_TO: $src1 = $dst |
| 332 | wpos = CStr.find_first_of(Chars: " \t" , From: start); |
| 333 | if (wpos == StringRef::npos || wpos > pos) |
| 334 | PrintFatalError(ErrorLoc: Rec->getLoc(), |
| 335 | Msg: "Illegal format for tied-to constraint in '" + |
| 336 | Rec->getName() + "': '" + CStr + "'" ); |
| 337 | StringRef LHSOpName = CStr.substr(Start: start, N: wpos - start); |
| 338 | std::pair<unsigned, unsigned> LHSOp = Ops.ParseOperandName(Op: LHSOpName, AllowWholeOp: false); |
| 339 | |
| 340 | wpos = CStr.find_first_not_of(Chars: " \t" , From: pos + 1); |
| 341 | if (wpos == StringRef::npos) |
| 342 | PrintFatalError(ErrorLoc: Rec->getLoc(), |
| 343 | Msg: "Illegal format for tied-to constraint: '" + CStr + "'" ); |
| 344 | |
| 345 | StringRef RHSOpName = CStr.substr(Start: wpos); |
| 346 | std::pair<unsigned, unsigned> RHSOp = Ops.ParseOperandName(Op: RHSOpName, AllowWholeOp: false); |
| 347 | |
| 348 | // Sort the operands into order, which should put the output one |
| 349 | // first. But keep the original order, for use in diagnostics. |
| 350 | bool FirstIsDest = (LHSOp < RHSOp); |
| 351 | std::pair<unsigned, unsigned> DestOp = (FirstIsDest ? LHSOp : RHSOp); |
| 352 | StringRef DestOpName = (FirstIsDest ? LHSOpName : RHSOpName); |
| 353 | std::pair<unsigned, unsigned> SrcOp = (FirstIsDest ? RHSOp : LHSOp); |
| 354 | StringRef SrcOpName = (FirstIsDest ? RHSOpName : LHSOpName); |
| 355 | |
| 356 | // Ensure one operand is a def and the other is a use. |
| 357 | if (DestOp.first >= Ops.NumDefs) |
| 358 | PrintFatalError(ErrorLoc: Rec->getLoc(), Msg: "Input operands '" + LHSOpName + "' and '" + |
| 359 | RHSOpName + "' of '" + Rec->getName() + |
| 360 | "' cannot be tied!" ); |
| 361 | if (SrcOp.first < Ops.NumDefs) |
| 362 | PrintFatalError(ErrorLoc: Rec->getLoc(), Msg: "Output operands '" + LHSOpName + "' and '" + |
| 363 | RHSOpName + "' of '" + Rec->getName() + |
| 364 | "' cannot be tied!" ); |
| 365 | |
| 366 | // The constraint has to go on the operand with higher index, i.e. |
| 367 | // the source one. Check there isn't another constraint there |
| 368 | // already. |
| 369 | if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone()) |
| 370 | PrintFatalError(ErrorLoc: Rec->getLoc(), Msg: "Operand '" + SrcOpName + "' of '" + |
| 371 | Rec->getName() + |
| 372 | "' cannot have multiple constraints!" ); |
| 373 | |
| 374 | unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(Op: DestOp); |
| 375 | auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(Op: DestFlatOpNo); |
| 376 | |
| 377 | // Check that the earlier operand is not the target of another tie |
| 378 | // before making it the target of this one. |
| 379 | for (const CGIOperandList::OperandInfo &Op : Ops) { |
| 380 | for (unsigned i = 0; i < Op.MINumOperands; i++) |
| 381 | if (Op.Constraints[i] == NewConstraint) |
| 382 | PrintFatalError(ErrorLoc: Rec->getLoc(), |
| 383 | Msg: "Operand '" + DestOpName + "' of '" + Rec->getName() + |
| 384 | "' cannot have multiple operands tied to it!" ); |
| 385 | } |
| 386 | |
| 387 | Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint; |
| 388 | } |
| 389 | |
| 390 | static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, |
| 391 | const Record *Rec) { |
| 392 | if (CStr.empty()) |
| 393 | return; |
| 394 | |
| 395 | StringRef delims("," ); |
| 396 | StringRef::size_type bidx, eidx; |
| 397 | |
| 398 | bidx = CStr.find_first_not_of(Chars: delims); |
| 399 | while (bidx != StringRef::npos) { |
| 400 | eidx = CStr.find_first_of(Chars: delims, From: bidx); |
| 401 | if (eidx == StringRef::npos) |
| 402 | eidx = CStr.size(); |
| 403 | |
| 404 | ParseConstraint(CStr: CStr.substr(Start: bidx, N: eidx - bidx), Ops, Rec); |
| 405 | bidx = CStr.find_first_not_of(Chars: delims, From: eidx); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | void CGIOperandList::ProcessDisableEncoding(StringRef DisableEncoding) { |
| 410 | while (true) { |
| 411 | StringRef OpName; |
| 412 | std::tie(args&: OpName, args&: DisableEncoding) = getToken(Source: DisableEncoding, Delimiters: " ,\t" ); |
| 413 | if (OpName.empty()) |
| 414 | break; |
| 415 | |
| 416 | // Figure out which operand this is. |
| 417 | std::pair<unsigned, unsigned> Op = ParseOperandName(Op: OpName, AllowWholeOp: false); |
| 418 | |
| 419 | // Mark the operand as not-to-be encoded. |
| 420 | OperandList[Op.first].DoNotEncode[Op.second] = true; |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | //===----------------------------------------------------------------------===// |
| 425 | // CodeGenInstruction Implementation |
| 426 | //===----------------------------------------------------------------------===// |
| 427 | |
| 428 | CodeGenInstruction::CodeGenInstruction(const Record *R) |
| 429 | : TheDef(R), Operands(R), InferredFrom(nullptr) { |
| 430 | Namespace = R->getValueAsString(FieldName: "Namespace" ); |
| 431 | AsmString = R->getValueAsString(FieldName: "AsmString" ); |
| 432 | |
| 433 | isPreISelOpcode = R->getValueAsBit(FieldName: "isPreISelOpcode" ); |
| 434 | isReturn = R->getValueAsBit(FieldName: "isReturn" ); |
| 435 | isEHScopeReturn = R->getValueAsBit(FieldName: "isEHScopeReturn" ); |
| 436 | isBranch = R->getValueAsBit(FieldName: "isBranch" ); |
| 437 | isIndirectBranch = R->getValueAsBit(FieldName: "isIndirectBranch" ); |
| 438 | isCompare = R->getValueAsBit(FieldName: "isCompare" ); |
| 439 | isMoveImm = R->getValueAsBit(FieldName: "isMoveImm" ); |
| 440 | isMoveReg = R->getValueAsBit(FieldName: "isMoveReg" ); |
| 441 | isBitcast = R->getValueAsBit(FieldName: "isBitcast" ); |
| 442 | isSelect = R->getValueAsBit(FieldName: "isSelect" ); |
| 443 | isBarrier = R->getValueAsBit(FieldName: "isBarrier" ); |
| 444 | isCall = R->getValueAsBit(FieldName: "isCall" ); |
| 445 | isAdd = R->getValueAsBit(FieldName: "isAdd" ); |
| 446 | isTrap = R->getValueAsBit(FieldName: "isTrap" ); |
| 447 | canFoldAsLoad = R->getValueAsBit(FieldName: "canFoldAsLoad" ); |
| 448 | isPredicable = !R->getValueAsBit(FieldName: "isUnpredicable" ) && |
| 449 | (Operands.isPredicable || R->getValueAsBit(FieldName: "isPredicable" )); |
| 450 | isConvertibleToThreeAddress = R->getValueAsBit(FieldName: "isConvertibleToThreeAddress" ); |
| 451 | isCommutable = R->getValueAsBit(FieldName: "isCommutable" ); |
| 452 | isTerminator = R->getValueAsBit(FieldName: "isTerminator" ); |
| 453 | isReMaterializable = R->getValueAsBit(FieldName: "isReMaterializable" ); |
| 454 | hasDelaySlot = R->getValueAsBit(FieldName: "hasDelaySlot" ); |
| 455 | usesCustomInserter = R->getValueAsBit(FieldName: "usesCustomInserter" ); |
| 456 | hasPostISelHook = R->getValueAsBit(FieldName: "hasPostISelHook" ); |
| 457 | hasCtrlDep = R->getValueAsBit(FieldName: "hasCtrlDep" ); |
| 458 | isNotDuplicable = R->getValueAsBit(FieldName: "isNotDuplicable" ); |
| 459 | isRegSequence = R->getValueAsBit(FieldName: "isRegSequence" ); |
| 460 | isExtractSubreg = R->getValueAsBit(FieldName: "isExtractSubreg" ); |
| 461 | isInsertSubreg = R->getValueAsBit(FieldName: "isInsertSubreg" ); |
| 462 | isConvergent = R->getValueAsBit(FieldName: "isConvergent" ); |
| 463 | hasNoSchedulingInfo = R->getValueAsBit(FieldName: "hasNoSchedulingInfo" ); |
| 464 | FastISelShouldIgnore = R->getValueAsBit(FieldName: "FastISelShouldIgnore" ); |
| 465 | variadicOpsAreDefs = R->getValueAsBit(FieldName: "variadicOpsAreDefs" ); |
| 466 | isAuthenticated = R->getValueAsBit(FieldName: "isAuthenticated" ); |
| 467 | |
| 468 | bool Unset; |
| 469 | mayLoad = R->getValueAsBitOrUnset(FieldName: "mayLoad" , Unset); |
| 470 | mayLoad_Unset = Unset; |
| 471 | mayStore = R->getValueAsBitOrUnset(FieldName: "mayStore" , Unset); |
| 472 | mayStore_Unset = Unset; |
| 473 | mayRaiseFPException = R->getValueAsBit(FieldName: "mayRaiseFPException" ); |
| 474 | hasSideEffects = R->getValueAsBitOrUnset(FieldName: "hasSideEffects" , Unset); |
| 475 | hasSideEffects_Unset = Unset; |
| 476 | |
| 477 | isAsCheapAsAMove = R->getValueAsBit(FieldName: "isAsCheapAsAMove" ); |
| 478 | hasExtraSrcRegAllocReq = R->getValueAsBit(FieldName: "hasExtraSrcRegAllocReq" ); |
| 479 | hasExtraDefRegAllocReq = R->getValueAsBit(FieldName: "hasExtraDefRegAllocReq" ); |
| 480 | isCodeGenOnly = R->getValueAsBit(FieldName: "isCodeGenOnly" ); |
| 481 | isPseudo = R->getValueAsBit(FieldName: "isPseudo" ); |
| 482 | isMeta = R->getValueAsBit(FieldName: "isMeta" ); |
| 483 | ImplicitDefs = R->getValueAsListOfDefs(FieldName: "Defs" ); |
| 484 | ImplicitUses = R->getValueAsListOfDefs(FieldName: "Uses" ); |
| 485 | |
| 486 | // This flag is only inferred from the pattern. |
| 487 | hasChain = false; |
| 488 | hasChain_Inferred = false; |
| 489 | |
| 490 | // Parse Constraints. |
| 491 | ParseConstraints(CStr: R->getValueAsString(FieldName: "Constraints" ), Ops&: Operands, Rec: R); |
| 492 | |
| 493 | // Parse the DisableEncoding field. |
| 494 | Operands.ProcessDisableEncoding(DisableEncoding: R->getValueAsString(FieldName: "DisableEncoding" )); |
| 495 | |
| 496 | // First check for a ComplexDeprecationPredicate. |
| 497 | if (R->getValue(Name: "ComplexDeprecationPredicate" )) { |
| 498 | HasComplexDeprecationPredicate = true; |
| 499 | DeprecatedReason = R->getValueAsString(FieldName: "ComplexDeprecationPredicate" ).str(); |
| 500 | } else if (const RecordVal *Dep = R->getValue(Name: "DeprecatedFeatureMask" )) { |
| 501 | // Check if we have a Subtarget feature mask. |
| 502 | HasComplexDeprecationPredicate = false; |
| 503 | DeprecatedReason = Dep->getValue()->getAsString(); |
| 504 | } else { |
| 505 | // This instruction isn't deprecated. |
| 506 | HasComplexDeprecationPredicate = false; |
| 507 | DeprecatedReason = "" ; |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | /// HasOneImplicitDefWithKnownVT - If the instruction has at least one |
| 512 | /// implicit def and it has a known VT, return the VT, otherwise return |
| 513 | /// MVT::Other. |
| 514 | MVT::SimpleValueType CodeGenInstruction::HasOneImplicitDefWithKnownVT( |
| 515 | const CodeGenTarget &TargetInfo) const { |
| 516 | if (ImplicitDefs.empty()) |
| 517 | return MVT::Other; |
| 518 | |
| 519 | // Check to see if the first implicit def has a resolvable type. |
| 520 | const Record *FirstImplicitDef = ImplicitDefs[0]; |
| 521 | assert(FirstImplicitDef->isSubClassOf("Register" )); |
| 522 | const std::vector<ValueTypeByHwMode> &RegVTs = |
| 523 | TargetInfo.getRegisterVTs(R: FirstImplicitDef); |
| 524 | if (RegVTs.size() == 1 && RegVTs[0].isSimple()) |
| 525 | return RegVTs[0].getSimple().SimpleTy; |
| 526 | return MVT::Other; |
| 527 | } |
| 528 | |
| 529 | /// FlattenAsmStringVariants - Flatten the specified AsmString to only |
| 530 | /// include text from the specified variant, returning the new string. |
| 531 | std::string CodeGenInstruction::FlattenAsmStringVariants(StringRef Cur, |
| 532 | unsigned Variant) { |
| 533 | std::string Res; |
| 534 | |
| 535 | for (;;) { |
| 536 | // Find the start of the next variant string. |
| 537 | size_t VariantsStart = 0; |
| 538 | for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart) |
| 539 | if (Cur[VariantsStart] == '{' && |
| 540 | (VariantsStart == 0 || |
| 541 | (Cur[VariantsStart - 1] != '$' && Cur[VariantsStart - 1] != '\\'))) |
| 542 | break; |
| 543 | |
| 544 | // Add the prefix to the result. |
| 545 | Res += Cur.slice(Start: 0, End: VariantsStart); |
| 546 | if (VariantsStart == Cur.size()) |
| 547 | break; |
| 548 | |
| 549 | ++VariantsStart; // Skip the '{'. |
| 550 | |
| 551 | // Scan to the end of the variants string. |
| 552 | size_t VariantsEnd = VariantsStart; |
| 553 | unsigned NestedBraces = 1; |
| 554 | for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) { |
| 555 | if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd - 1] != '\\') { |
| 556 | if (--NestedBraces == 0) |
| 557 | break; |
| 558 | } else if (Cur[VariantsEnd] == '{') |
| 559 | ++NestedBraces; |
| 560 | } |
| 561 | |
| 562 | // Select the Nth variant (or empty). |
| 563 | StringRef Selection = |
| 564 | Cur.substr(Start: VariantsStart, N: VariantsEnd - VariantsStart); |
| 565 | for (unsigned i = 0; i != Variant; ++i) |
| 566 | Selection = Selection.split(Separator: '|').second; |
| 567 | Res += Selection.split(Separator: '|').first; |
| 568 | |
| 569 | assert(VariantsEnd != Cur.size() && |
| 570 | "Unterminated variants in assembly string!" ); |
| 571 | Cur = Cur.substr(Start: VariantsEnd + 1); |
| 572 | } |
| 573 | |
| 574 | return Res; |
| 575 | } |
| 576 | |
| 577 | bool CodeGenInstruction::isOperandImpl(StringRef OpListName, unsigned i, |
| 578 | StringRef PropertyName) const { |
| 579 | const DagInit *ConstraintList = TheDef->getValueAsDag(FieldName: OpListName); |
| 580 | if (!ConstraintList || i >= ConstraintList->getNumArgs()) |
| 581 | return false; |
| 582 | |
| 583 | const DefInit *Constraint = dyn_cast<DefInit>(Val: ConstraintList->getArg(Num: i)); |
| 584 | if (!Constraint) |
| 585 | return false; |
| 586 | |
| 587 | return Constraint->getDef()->isSubClassOf(Name: "TypedOperand" ) && |
| 588 | Constraint->getDef()->getValueAsBit(FieldName: PropertyName); |
| 589 | } |
| 590 | |