Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 1 | //===- DAGISelEmitter.cpp - Generate an instruction selector --------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by Chris Lattner and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This tablegen backend emits a DAG instruction selector. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "DAGISelEmitter.h" |
| 15 | #include "Record.h" |
| 16 | #include "llvm/ADT/StringExtras.h" |
| 17 | #include "llvm/Support/Debug.h" |
| 18 | #include <set> |
| 19 | using namespace llvm; |
| 20 | |
Chris Lattner | ca559d0 | 2005-09-08 21:03:01 +0000 | [diff] [blame^] | 21 | //===----------------------------------------------------------------------===// |
| 22 | // SDNodeInfo implementation |
| 23 | // |
| 24 | SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { |
| 25 | EnumName = R->getValueAsString("Opcode"); |
| 26 | SDClassName = R->getValueAsString("SDClass"); |
| 27 | } |
Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 28 | |
| 29 | //===----------------------------------------------------------------------===// |
| 30 | // TreePatternNode implementation |
| 31 | // |
| 32 | |
| 33 | TreePatternNode::~TreePatternNode() { |
| 34 | #if 0 // FIXME: implement refcounted tree nodes! |
| 35 | for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| 36 | delete getChild(i); |
| 37 | #endif |
| 38 | } |
| 39 | |
| 40 | void TreePatternNode::print(std::ostream &OS) const { |
| 41 | if (isLeaf()) { |
| 42 | OS << *getLeafValue(); |
| 43 | } else { |
| 44 | OS << "(" << getOperator()->getName(); |
| 45 | } |
| 46 | |
| 47 | if (getType() == MVT::Other) |
| 48 | OS << ":Other"; |
| 49 | else if (getType() == MVT::LAST_VALUETYPE) |
| 50 | ;//OS << ":?"; |
| 51 | else |
| 52 | OS << ":" << getType(); |
| 53 | |
| 54 | if (!isLeaf()) { |
| 55 | if (getNumChildren() != 0) { |
| 56 | OS << " "; |
| 57 | getChild(0)->print(OS); |
| 58 | for (unsigned i = 1, e = getNumChildren(); i != e; ++i) { |
| 59 | OS << ", "; |
| 60 | getChild(i)->print(OS); |
| 61 | } |
| 62 | } |
| 63 | OS << ")"; |
| 64 | } |
| 65 | |
| 66 | if (!PredicateFn.empty()) |
| 67 | OS << "<<" << PredicateFn << ">>"; |
| 68 | if (!getName().empty()) |
| 69 | OS << ":$" << getName(); |
| 70 | |
| 71 | } |
| 72 | void TreePatternNode::dump() const { |
| 73 | print(std::cerr); |
| 74 | } |
| 75 | |
| 76 | /// clone - Make a copy of this tree and all of its children. |
| 77 | /// |
| 78 | TreePatternNode *TreePatternNode::clone() const { |
| 79 | TreePatternNode *New; |
| 80 | if (isLeaf()) { |
| 81 | New = new TreePatternNode(getLeafValue()); |
| 82 | } else { |
| 83 | std::vector<TreePatternNode*> CChildren; |
| 84 | CChildren.reserve(Children.size()); |
| 85 | for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| 86 | CChildren.push_back(getChild(i)->clone()); |
| 87 | New = new TreePatternNode(getOperator(), CChildren); |
| 88 | } |
| 89 | New->setName(getName()); |
| 90 | New->setType(getType()); |
| 91 | New->setPredicateFn(getPredicateFn()); |
| 92 | return New; |
| 93 | } |
| 94 | |
| 95 | void TreePatternNode:: |
| 96 | SubstituteFormalArguments(std::map<std::string, TreePatternNode*> &ArgMap) { |
| 97 | if (isLeaf()) return; |
| 98 | |
| 99 | for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { |
| 100 | TreePatternNode *Child = getChild(i); |
| 101 | if (Child->isLeaf()) { |
| 102 | Init *Val = Child->getLeafValue(); |
| 103 | if (dynamic_cast<DefInit*>(Val) && |
| 104 | static_cast<DefInit*>(Val)->getDef()->getName() == "node") { |
| 105 | // We found a use of a formal argument, replace it with its value. |
| 106 | Child = ArgMap[Child->getName()]; |
| 107 | assert(Child && "Couldn't find formal argument!"); |
| 108 | setChild(i, Child); |
| 109 | } |
| 110 | } else { |
| 111 | getChild(i)->SubstituteFormalArguments(ArgMap); |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | |
| 117 | /// InlinePatternFragments - If this pattern refers to any pattern |
| 118 | /// fragments, inline them into place, giving us a pattern without any |
| 119 | /// PatFrag references. |
| 120 | TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { |
| 121 | if (isLeaf()) return this; // nothing to do. |
| 122 | Record *Op = getOperator(); |
| 123 | |
| 124 | if (!Op->isSubClassOf("PatFrag")) { |
| 125 | // Just recursively inline children nodes. |
| 126 | for (unsigned i = 0, e = getNumChildren(); i != e; ++i) |
| 127 | setChild(i, getChild(i)->InlinePatternFragments(TP)); |
| 128 | return this; |
| 129 | } |
| 130 | |
| 131 | // Otherwise, we found a reference to a fragment. First, look up its |
| 132 | // TreePattern record. |
| 133 | TreePattern *Frag = TP.getDAGISelEmitter().getPatternFragment(Op); |
| 134 | |
| 135 | // Verify that we are passing the right number of operands. |
| 136 | if (Frag->getNumArgs() != Children.size()) |
| 137 | TP.error("'" + Op->getName() + "' fragment requires " + |
| 138 | utostr(Frag->getNumArgs()) + " operands!"); |
| 139 | |
| 140 | TreePatternNode *FragTree = Frag->getTrees()[0]->clone(); |
| 141 | |
| 142 | // Resolve formal arguments to their actual value. |
| 143 | if (Frag->getNumArgs()) { |
| 144 | // Compute the map of formal to actual arguments. |
| 145 | std::map<std::string, TreePatternNode*> ArgMap; |
| 146 | for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) |
| 147 | ArgMap[Frag->getArgName(i)] = getChild(i)->InlinePatternFragments(TP); |
| 148 | |
| 149 | FragTree->SubstituteFormalArguments(ArgMap); |
| 150 | } |
| 151 | |
Chris Lattner | fbf8e57 | 2005-09-08 17:45:12 +0000 | [diff] [blame] | 152 | FragTree->setName(getName()); |
| 153 | |
Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 154 | // Get a new copy of this fragment to stitch into here. |
| 155 | //delete this; // FIXME: implement refcounting! |
| 156 | return FragTree; |
| 157 | } |
| 158 | |
| 159 | //===----------------------------------------------------------------------===// |
| 160 | // TreePattern implementation |
| 161 | // |
| 162 | |
| 163 | TreePattern::TreePattern(PatternType pty, Record *TheRec, |
| 164 | const std::vector<DagInit *> &RawPat, |
| 165 | DAGISelEmitter &ise) |
| 166 | : PTy(pty), TheRecord(TheRec), ISE(ise) { |
| 167 | |
| 168 | for (unsigned i = 0, e = RawPat.size(); i != e; ++i) |
| 169 | Trees.push_back(ParseTreePattern(RawPat[i])); |
| 170 | |
| 171 | // Sanity checks and cleanup. |
| 172 | switch (PTy) { |
| 173 | case PatFrag: { |
| 174 | assert(Trees.size() == 1 && "How can we have more than one pattern here?"); |
| 175 | |
| 176 | // Validate arguments list, convert it to map, to discard duplicates. |
| 177 | std::set<std::string> OperandsMap(Args.begin(), Args.end()); |
| 178 | |
| 179 | if (OperandsMap.count("")) |
| 180 | error("Cannot have unnamed 'node' values in pattern fragment!"); |
| 181 | |
| 182 | // Parse the operands list. |
| 183 | DagInit *OpsList = TheRec->getValueAsDag("Operands"); |
| 184 | if (OpsList->getNodeType()->getName() != "ops") |
| 185 | error("Operands list should start with '(ops ... '!"); |
| 186 | |
| 187 | // Copy over the arguments. |
| 188 | Args.clear(); |
| 189 | for (unsigned i = 0, e = OpsList->getNumArgs(); i != e; ++i) { |
| 190 | if (!dynamic_cast<DefInit*>(OpsList->getArg(i)) || |
| 191 | static_cast<DefInit*>(OpsList->getArg(i))-> |
| 192 | getDef()->getName() != "node") |
| 193 | error("Operands list should all be 'node' values."); |
| 194 | if (OpsList->getArgName(i).empty()) |
| 195 | error("Operands list should have names for each operand!"); |
| 196 | if (!OperandsMap.count(OpsList->getArgName(i))) |
| 197 | error("'" + OpsList->getArgName(i) + |
| 198 | "' does not occur in pattern or was multiply specified!"); |
| 199 | OperandsMap.erase(OpsList->getArgName(i)); |
| 200 | Args.push_back(OpsList->getArgName(i)); |
| 201 | } |
| 202 | |
| 203 | if (!OperandsMap.empty()) |
| 204 | error("Operands list does not contain an entry for operand '" + |
| 205 | *OperandsMap.begin() + "'!"); |
| 206 | |
| 207 | break; |
| 208 | } |
| 209 | default: |
| 210 | if (!Args.empty()) |
| 211 | error("Only pattern fragments can have operands (use 'node' values)!"); |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | void TreePattern::error(const std::string &Msg) const { |
| 217 | std::string M = "In "; |
| 218 | switch (PTy) { |
| 219 | case PatFrag: M += "patfrag "; break; |
| 220 | case Instruction: M += "instruction "; break; |
| 221 | } |
| 222 | throw M + TheRecord->getName() + ": " + Msg; |
| 223 | } |
| 224 | |
| 225 | /// getIntrinsicType - Check to see if the specified record has an intrinsic |
| 226 | /// type which should be applied to it. This infer the type of register |
| 227 | /// references from the register file information, for example. |
| 228 | /// |
| 229 | MVT::ValueType TreePattern::getIntrinsicType(Record *R) const { |
| 230 | // Check to see if this is a register or a register class... |
| 231 | if (R->isSubClassOf("RegisterClass")) |
| 232 | return getValueType(R->getValueAsDef("RegType")); |
| 233 | else if (R->isSubClassOf("PatFrag")) { |
| 234 | //return ISE.ReadNonterminal(R)->getTree()->getType(); |
| 235 | return MVT::LAST_VALUETYPE; |
| 236 | } else if (R->isSubClassOf("Register")) { |
| 237 | assert(0 && "Explicit registers not handled here yet!\n"); |
| 238 | return MVT::LAST_VALUETYPE; |
| 239 | } else if (R->isSubClassOf("ValueType")) { |
| 240 | // Using a VTSDNode. |
| 241 | return MVT::Other; |
| 242 | } else if (R->getName() == "node") { |
| 243 | // Placeholder. |
| 244 | return MVT::LAST_VALUETYPE; |
| 245 | } |
| 246 | |
| 247 | error("Unknown value used: " + R->getName()); |
| 248 | return MVT::Other; |
| 249 | } |
| 250 | |
| 251 | TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) { |
| 252 | Record *Operator = Dag->getNodeType(); |
| 253 | |
| 254 | if (Operator->isSubClassOf("ValueType")) { |
| 255 | // If the operator is a ValueType, then this must be "type cast" of a leaf |
| 256 | // node. |
| 257 | if (Dag->getNumArgs() != 1) |
| 258 | error("Type cast only valid for a leaf node!"); |
| 259 | |
| 260 | Init *Arg = Dag->getArg(0); |
| 261 | TreePatternNode *New; |
| 262 | if (DefInit *DI = dynamic_cast<DefInit*>(Arg)) { |
| 263 | New = new TreePatternNode(DI); |
| 264 | // If it's a regclass or something else known, set the type. |
| 265 | New->setType(getIntrinsicType(DI->getDef())); |
| 266 | } else if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) { |
| 267 | New = ParseTreePattern(DI); |
| 268 | } else { |
| 269 | Arg->dump(); |
| 270 | error("Unknown leaf value for tree pattern!"); |
| 271 | return 0; |
| 272 | } |
| 273 | |
| 274 | // Apply the type cast... |
| 275 | assert(0 && "unimp yet"); |
| 276 | //New->updateNodeType(getValueType(Operator), TheRecord->getName()); |
| 277 | return New; |
| 278 | } |
| 279 | |
| 280 | // Verify that this is something that makes sense for an operator. |
| 281 | if (!Operator->isSubClassOf("PatFrag") && !Operator->isSubClassOf("SDNode") && |
| 282 | Operator->getName() != "set") |
| 283 | error("Unrecognized node '" + Operator->getName() + "'!"); |
| 284 | |
| 285 | std::vector<TreePatternNode*> Children; |
| 286 | |
| 287 | for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { |
| 288 | Init *Arg = Dag->getArg(i); |
| 289 | if (DagInit *DI = dynamic_cast<DagInit*>(Arg)) { |
| 290 | Children.push_back(ParseTreePattern(DI)); |
| 291 | Children.back()->setName(Dag->getArgName(i)); |
| 292 | } else if (DefInit *DefI = dynamic_cast<DefInit*>(Arg)) { |
| 293 | Record *R = DefI->getDef(); |
| 294 | // Direct reference to a leaf DagNode or PatFrag? Turn it into a |
| 295 | // TreePatternNode if its own. |
| 296 | if (R->isSubClassOf("SDNode") || R->isSubClassOf("PatFrag")) { |
| 297 | Dag->setArg(i, new DagInit(R, |
| 298 | std::vector<std::pair<Init*, std::string> >())); |
| 299 | --i; // Revisit this node... |
| 300 | } else { |
| 301 | TreePatternNode *Node = new TreePatternNode(DefI); |
| 302 | Node->setName(Dag->getArgName(i)); |
| 303 | Children.push_back(Node); |
| 304 | |
| 305 | // If it's a regclass or something else known, set the type. |
| 306 | Node->setType(getIntrinsicType(R)); |
| 307 | |
| 308 | // Input argument? |
| 309 | if (R->getName() == "node") { |
| 310 | if (Dag->getArgName(i).empty()) |
| 311 | error("'node' argument requires a name to match with operand list"); |
| 312 | Args.push_back(Dag->getArgName(i)); |
| 313 | } |
| 314 | } |
| 315 | } else { |
| 316 | Arg->dump(); |
| 317 | error("Unknown leaf value for tree pattern!"); |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | return new TreePatternNode(Operator, Children); |
| 322 | } |
| 323 | |
| 324 | void TreePattern::print(std::ostream &OS) const { |
| 325 | switch (getPatternType()) { |
| 326 | case TreePattern::PatFrag: OS << "PatFrag pattern "; break; |
| 327 | case TreePattern::Instruction: OS << "Inst pattern "; break; |
| 328 | } |
| 329 | |
| 330 | OS << getRecord()->getName(); |
| 331 | if (!Args.empty()) { |
| 332 | OS << "(" << Args[0]; |
| 333 | for (unsigned i = 1, e = Args.size(); i != e; ++i) |
| 334 | OS << ", " << Args[i]; |
| 335 | OS << ")"; |
| 336 | } |
| 337 | OS << ": "; |
| 338 | |
| 339 | if (Trees.size() > 1) |
| 340 | OS << "[\n"; |
| 341 | for (unsigned i = 0, e = Trees.size(); i != e; ++i) { |
| 342 | OS << "\t"; |
| 343 | Trees[i]->print(OS); |
| 344 | OS << "\n"; |
| 345 | } |
| 346 | |
| 347 | if (Trees.size() > 1) |
| 348 | OS << "]\n"; |
| 349 | } |
| 350 | |
| 351 | void TreePattern::dump() const { print(std::cerr); } |
| 352 | |
| 353 | |
| 354 | |
| 355 | //===----------------------------------------------------------------------===// |
| 356 | // DAGISelEmitter implementation |
| 357 | // |
| 358 | |
Chris Lattner | ca559d0 | 2005-09-08 21:03:01 +0000 | [diff] [blame^] | 359 | // Parse all of the SDNode definitions for the target, populating SDNodes. |
| 360 | void DAGISelEmitter::ParseNodeInfo() { |
| 361 | std::vector<Record*> Nodes = Records.getAllDerivedDefinitions("SDNode"); |
| 362 | while (!Nodes.empty()) { |
| 363 | SDNodes.insert(std::make_pair(Nodes.back(), Nodes.back())); |
| 364 | Nodes.pop_back(); |
| 365 | } |
| 366 | } |
| 367 | |
Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 368 | /// ParseAndResolvePatternFragments - Parse all of the PatFrag definitions in |
| 369 | /// the .td file, building up the PatternFragments map. After we've collected |
| 370 | /// them all, inline fragments together as necessary, so that there are no |
| 371 | /// references left inside a pattern fragment to a pattern fragment. |
| 372 | /// |
| 373 | /// This also emits all of the predicate functions to the output file. |
| 374 | /// |
| 375 | void DAGISelEmitter::ParseAndResolvePatternFragments(std::ostream &OS) { |
| 376 | std::vector<Record*> Fragments = Records.getAllDerivedDefinitions("PatFrag"); |
| 377 | |
| 378 | // First step, parse all of the fragments and emit predicate functions. |
| 379 | OS << "\n// Predicate functions.\n"; |
| 380 | for (unsigned i = 0, e = Fragments.size(); i != e; ++i) { |
| 381 | std::vector<DagInit*> Trees; |
| 382 | Trees.push_back(Fragments[i]->getValueAsDag("Fragment")); |
| 383 | TreePattern *P = new TreePattern(TreePattern::PatFrag, Fragments[i], |
| 384 | Trees, *this); |
| 385 | PatternFragments[Fragments[i]] = P; |
| 386 | |
| 387 | // If there is a code init for this fragment, emit the predicate code and |
| 388 | // keep track of the fact that this fragment uses it. |
| 389 | CodeInit *CI = |
| 390 | dynamic_cast<CodeInit*>(Fragments[i]->getValueInit("Predicate")); |
| 391 | if (!CI->getValue().empty()) { |
| 392 | assert(!P->getTrees()[0]->isLeaf() && "Can't be a leaf!"); |
| 393 | std::string ClassName = |
| 394 | P->getTrees()[0]->getOperator()->getValueAsString("SDClass"); |
| 395 | const char *C2 = ClassName == "SDNode" ? "N" : "inN"; |
| 396 | |
| 397 | OS << "static inline bool Predicate_" << Fragments[i]->getName() |
| 398 | << "(SDNode *" << C2 << ") {\n"; |
| 399 | if (ClassName != "SDNode") |
| 400 | OS << " " << ClassName << " *N = cast<" << ClassName << ">(inN);\n"; |
| 401 | OS << CI->getValue() << "\n}\n"; |
| 402 | P->getTrees()[0]->setPredicateFn("Predicate_"+Fragments[i]->getName()); |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | OS << "\n\n"; |
| 407 | |
| 408 | // Now that we've parsed all of the tree fragments, do a closure on them so |
| 409 | // that there are not references to PatFrags left inside of them. |
| 410 | for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(), |
| 411 | E = PatternFragments.end(); I != E; ++I) { |
| 412 | I->second->InlinePatternFragments(); |
| 413 | // If debugging, print out the pattern fragment result. |
| 414 | DEBUG(I->second->dump()); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | /// ParseAndResolveInstructions - Parse all of the instructions, inlining and |
| 419 | /// resolving any fragments involved. This populates the Instructions list with |
| 420 | /// fully resolved instructions. |
| 421 | void DAGISelEmitter::ParseAndResolveInstructions() { |
| 422 | std::vector<Record*> Instrs = Records.getAllDerivedDefinitions("Instruction"); |
| 423 | |
| 424 | for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { |
| 425 | if (!dynamic_cast<ListInit*>(Instrs[i]->getValueInit("Pattern"))) |
| 426 | continue; // no pattern yet, ignore it. |
| 427 | |
| 428 | ListInit *LI = Instrs[i]->getValueAsListInit("Pattern"); |
| 429 | if (LI->getSize() == 0) continue; // no pattern. |
| 430 | |
| 431 | std::vector<DagInit*> Trees; |
| 432 | for (unsigned j = 0, e = LI->getSize(); j != e; ++j) |
| 433 | Trees.push_back((DagInit*)LI->getElement(j)); |
| 434 | |
| 435 | // Parse the instruction. |
| 436 | Instructions.push_back(new TreePattern(TreePattern::Instruction, Instrs[i], |
| 437 | Trees, *this)); |
| 438 | // Inline pattern fragments into it. |
| 439 | Instructions.back()->InlinePatternFragments(); |
| 440 | |
Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 441 | DEBUG(Instructions.back()->dump()); |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { |
| 446 | // Emit boilerplate. |
| 447 | OS << "// The main instruction selector code.\n" |
| 448 | << "SDOperand " << Target.getName() |
| 449 | << "DAGToDAGISel::SelectCode(SDOperand Op) {\n" |
| 450 | << " SDNode *N = Op.Val;\n" |
| 451 | << " if (N->getOpcode() >= ISD::BUILTIN_OP_END &&\n" |
| 452 | << " N->getOpcode() < PPCISD::FIRST_NUMBER)\n" |
| 453 | << " return Op; // Already selected.\n\n" |
| 454 | << " switch (N->getOpcode()) {\n" |
| 455 | << " default: break;\n" |
| 456 | << " case ISD::EntryToken: // These leaves remain the same.\n" |
| 457 | << " return Op;\n" |
| 458 | << " case ISD::AssertSext:\n" |
| 459 | << " case ISD::AssertZext:\n" |
| 460 | << " return Select(N->getOperand(0));\n"; |
| 461 | |
| 462 | |
| 463 | |
| 464 | OS << " } // end of big switch.\n\n" |
| 465 | << " std::cerr << \"Cannot yet select: \";\n" |
| 466 | << " N->dump();\n" |
| 467 | << " std::cerr << '\\n';\n" |
| 468 | << " abort();\n" |
| 469 | << "}\n"; |
| 470 | } |
| 471 | |
| 472 | |
| 473 | void DAGISelEmitter::run(std::ostream &OS) { |
| 474 | EmitSourceFileHeader("DAG Instruction Selector for the " + Target.getName() + |
| 475 | " target", OS); |
| 476 | |
Chris Lattner | ca559d0 | 2005-09-08 21:03:01 +0000 | [diff] [blame^] | 477 | ParseNodeInfo(); |
Chris Lattner | 54cb8fd | 2005-09-07 23:44:43 +0000 | [diff] [blame] | 478 | ParseAndResolvePatternFragments(OS); |
| 479 | ParseAndResolveInstructions(); |
| 480 | |
| 481 | // TODO: convert some instructions to expanders if needed or something. |
| 482 | |
| 483 | EmitInstructionSelector(OS); |
| 484 | |
| 485 | for (std::map<Record*, TreePattern*>::iterator I = PatternFragments.begin(), |
| 486 | E = PatternFragments.end(); I != E; ++I) |
| 487 | delete I->second; |
| 488 | PatternFragments.clear(); |
| 489 | |
| 490 | for (unsigned i = 0, e = Instructions.size(); i != e; ++i) |
| 491 | delete Instructions[i]; |
| 492 | Instructions.clear(); |
| 493 | } |