js/src/jit/ValueNumbering.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/ValueNumbering.h"
michael@0 8
michael@0 9 #include "jit/IonSpewer.h"
michael@0 10 #include "jit/MIRGenerator.h"
michael@0 11 #include "jit/MIRGraph.h"
michael@0 12
michael@0 13 using namespace js;
michael@0 14 using namespace js::jit;
michael@0 15
michael@0 16 ValueNumberer::ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic)
michael@0 17 : mir(mir),
michael@0 18 graph_(graph),
michael@0 19 values(graph.alloc()),
michael@0 20 pessimisticPass_(!optimistic),
michael@0 21 count_(0)
michael@0 22 { }
michael@0 23
michael@0 24 TempAllocator &
michael@0 25 ValueNumberer::alloc() const
michael@0 26 {
michael@0 27 return graph_.alloc();
michael@0 28 }
michael@0 29
michael@0 30 uint32_t
michael@0 31 ValueNumberer::lookupValue(MDefinition *ins)
michael@0 32 {
michael@0 33 ValueMap::AddPtr p = values.lookupForAdd(ins);
michael@0 34 if (p) {
michael@0 35 // make sure this is in the correct group
michael@0 36 setClass(ins, p->key());
michael@0 37 return p->value();
michael@0 38 }
michael@0 39
michael@0 40 if (!values.add(p, ins, ins->id()))
michael@0 41 return 0;
michael@0 42 breakClass(ins);
michael@0 43
michael@0 44 return ins->id();
michael@0 45 }
michael@0 46
michael@0 47 MDefinition *
michael@0 48 ValueNumberer::simplify(MDefinition *def, bool useValueNumbers)
michael@0 49 {
michael@0 50 if (def->isEffectful())
michael@0 51 return def;
michael@0 52
michael@0 53 MDefinition *ins = def->foldsTo(alloc(), useValueNumbers);
michael@0 54 if (ins == def)
michael@0 55 return def;
michael@0 56
michael@0 57 // Ensure this instruction has a value number.
michael@0 58 if (!ins->valueNumberData())
michael@0 59 ins->setValueNumberData(new(alloc()) ValueNumberData);
michael@0 60
michael@0 61 if (!ins->block()) {
michael@0 62 // In this case, we made a new def by constant folding, for
michael@0 63 // example, we replaced add(#3,#4) with a new const(#7) node.
michael@0 64
michael@0 65 // We will only fold a phi into one of its operands.
michael@0 66 JS_ASSERT(!def->isPhi());
michael@0 67
michael@0 68 def->block()->insertAfter(def->toInstruction(), ins->toInstruction());
michael@0 69 ins->setValueNumber(lookupValue(ins));
michael@0 70 }
michael@0 71
michael@0 72 JS_ASSERT(ins->id() != 0);
michael@0 73
michael@0 74 def->replaceAllUsesWith(ins);
michael@0 75
michael@0 76 IonSpew(IonSpew_GVN, "Folding %d to be %d", def->id(), ins->id());
michael@0 77 return ins;
michael@0 78 }
michael@0 79
michael@0 80 MControlInstruction *
michael@0 81 ValueNumberer::simplifyControlInstruction(MControlInstruction *def)
michael@0 82 {
michael@0 83 if (def->isEffectful())
michael@0 84 return def;
michael@0 85
michael@0 86 MDefinition *repl = def->foldsTo(alloc(), false);
michael@0 87 if (repl == def)
michael@0 88 return def;
michael@0 89
michael@0 90 // Ensure this instruction has a value number.
michael@0 91 if (!repl->valueNumberData())
michael@0 92 repl->setValueNumberData(new(alloc()) ValueNumberData);
michael@0 93
michael@0 94 MBasicBlock *block = def->block();
michael@0 95
michael@0 96 // MControlInstructions should not have consumers.
michael@0 97 JS_ASSERT(repl->isControlInstruction());
michael@0 98 JS_ASSERT(!def->hasUses());
michael@0 99
michael@0 100 if (def->isInWorklist())
michael@0 101 repl->setInWorklist();
michael@0 102
michael@0 103 block->discardLastIns();
michael@0 104 block->end((MControlInstruction *)repl);
michael@0 105 return (MControlInstruction *)repl;
michael@0 106 }
michael@0 107
michael@0 108 void
michael@0 109 ValueNumberer::markDefinition(MDefinition *def)
michael@0 110 {
michael@0 111 if (isMarked(def))
michael@0 112 return;
michael@0 113
michael@0 114 IonSpew(IonSpew_GVN, "marked %d", def->id());
michael@0 115 def->setInWorklist();
michael@0 116 count_++;
michael@0 117 }
michael@0 118
michael@0 119 void
michael@0 120 ValueNumberer::unmarkDefinition(MDefinition *def)
michael@0 121 {
michael@0 122 if (pessimisticPass_)
michael@0 123 return;
michael@0 124
michael@0 125 JS_ASSERT(count_ > 0);
michael@0 126 IonSpew(IonSpew_GVN, "unmarked %d", def->id());
michael@0 127 def->setNotInWorklist();
michael@0 128 count_--;
michael@0 129 }
michael@0 130
michael@0 131 void
michael@0 132 ValueNumberer::markBlock(MBasicBlock *block)
michael@0 133 {
michael@0 134 for (MDefinitionIterator iter(block); iter; iter++)
michael@0 135 markDefinition(*iter);
michael@0 136 markDefinition(block->lastIns());
michael@0 137 }
michael@0 138
michael@0 139 void
michael@0 140 ValueNumberer::markConsumers(MDefinition *def)
michael@0 141 {
michael@0 142 if (pessimisticPass_)
michael@0 143 return;
michael@0 144
michael@0 145 JS_ASSERT(!def->isInWorklist());
michael@0 146 JS_ASSERT(!def->isControlInstruction());
michael@0 147 for (MUseDefIterator use(def); use; use++)
michael@0 148 markDefinition(use.def());
michael@0 149 }
michael@0 150
michael@0 151 bool
michael@0 152 ValueNumberer::computeValueNumbers()
michael@0 153 {
michael@0 154 // At the end of this function, we will have the value numbering stored in
michael@0 155 // each instruction.
michael@0 156 //
michael@0 157 // We also need an "optimistic" value number, for temporary use, which is
michael@0 158 // stored in a hashtable.
michael@0 159 //
michael@0 160 // For the instruction x := y op z, we map (op, VN[y], VN[z]) to a value
michael@0 161 // number, say v. If it is not in the map, we use the instruction id.
michael@0 162 //
michael@0 163 // If the instruction in question's value number is not already
michael@0 164 // v, we break the congruence and set it to v. We repeat until saturation.
michael@0 165 // This will take at worst O(d) time, where d is the loop connectedness
michael@0 166 // of the SSA def/use graph.
michael@0 167 //
michael@0 168 // The algorithm is the simple RPO-based algorithm from
michael@0 169 // "SCC-Based Value Numbering" by Cooper and Simpson.
michael@0 170 //
michael@0 171 // If we are performing a pessimistic pass, then we assume that every
michael@0 172 // definition is in its own congruence class, since we know nothing about
michael@0 173 // values that enter Phi nodes through back edges. We then make one pass
michael@0 174 // through the graph, ignoring back edges. This yields less congruences on
michael@0 175 // any graph with back-edges, but is much faster to perform.
michael@0 176
michael@0 177 IonSpew(IonSpew_GVN, "Numbering instructions");
michael@0 178
michael@0 179 if (!values.init())
michael@0 180 return false;
michael@0 181 // Stick a VN object onto every mdefinition
michael@0 182 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 183 if (mir->shouldCancel("Value Numbering (preparation loop"))
michael@0 184 return false;
michael@0 185 for (MDefinitionIterator iter(*block); iter; iter++)
michael@0 186 iter->setValueNumberData(new(alloc()) ValueNumberData);
michael@0 187 MControlInstruction *jump = block->lastIns();
michael@0 188 jump->setValueNumberData(new(alloc()) ValueNumberData);
michael@0 189 }
michael@0 190
michael@0 191 // Assign unique value numbers if pessimistic.
michael@0 192 // It might be productive to do this in the MDefinition constructor or
michael@0 193 // possibly in a previous pass, if it seems reasonable.
michael@0 194 if (pessimisticPass_) {
michael@0 195 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 196 for (MDefinitionIterator iter(*block); iter; iter++)
michael@0 197 iter->setValueNumber(iter->id());
michael@0 198 }
michael@0 199 } else {
michael@0 200 // For each root block, add all of its instructions to the worklist.
michael@0 201 markBlock(*(graph_.begin()));
michael@0 202 if (graph_.osrBlock())
michael@0 203 markBlock(graph_.osrBlock());
michael@0 204 }
michael@0 205
michael@0 206 while (count_ > 0) {
michael@0 207 #ifdef DEBUG
michael@0 208 if (!pessimisticPass_) {
michael@0 209 size_t debugCount = 0;
michael@0 210 IonSpew(IonSpew_GVN, "The following instructions require processing:");
michael@0 211 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 212 for (MDefinitionIterator iter(*block); iter; iter++) {
michael@0 213 if (iter->isInWorklist()) {
michael@0 214 IonSpew(IonSpew_GVN, "\t%d", iter->id());
michael@0 215 debugCount++;
michael@0 216 }
michael@0 217 }
michael@0 218 if (block->lastIns()->isInWorklist()) {
michael@0 219 IonSpew(IonSpew_GVN, "\t%d", block->lastIns()->id());
michael@0 220 debugCount++;
michael@0 221 }
michael@0 222 }
michael@0 223 if (!debugCount)
michael@0 224 IonSpew(IonSpew_GVN, "\tNone");
michael@0 225 JS_ASSERT(debugCount == count_);
michael@0 226 }
michael@0 227 #endif
michael@0 228 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 229 if (mir->shouldCancel("Value Numbering (main loop)"))
michael@0 230 return false;
michael@0 231 for (MDefinitionIterator iter(*block); iter; ) {
michael@0 232
michael@0 233 if (!isMarked(*iter)) {
michael@0 234 iter++;
michael@0 235 continue;
michael@0 236 }
michael@0 237
michael@0 238 JS_ASSERT_IF(!pessimisticPass_, count_ > 0);
michael@0 239 unmarkDefinition(*iter);
michael@0 240
michael@0 241 MDefinition *ins = simplify(*iter, false);
michael@0 242
michael@0 243 if (ins != *iter) {
michael@0 244 iter = block->discardDefAt(iter);
michael@0 245 continue;
michael@0 246 }
michael@0 247
michael@0 248 // Don't bother storing this instruction in the HashMap if
michael@0 249 // (a) eliminateRedundancies will never eliminate it (because
michael@0 250 // it's non-movable or effectful) and (b) no other instruction's
michael@0 251 // value number depends on it.
michael@0 252 if (!ins->hasDefUses() && (!ins->isMovable() || ins->isEffectful())) {
michael@0 253 iter++;
michael@0 254 continue;
michael@0 255 }
michael@0 256
michael@0 257 uint32_t value = lookupValue(ins);
michael@0 258
michael@0 259 if (!value)
michael@0 260 return false; // Hashtable insertion failed
michael@0 261
michael@0 262 if (ins->valueNumber() != value) {
michael@0 263 IonSpew(IonSpew_GVN,
michael@0 264 "Broke congruence for instruction %d (%p) with VN %d (now using %d)",
michael@0 265 ins->id(), (void *) ins, ins->valueNumber(), value);
michael@0 266 ins->setValueNumber(value);
michael@0 267 markConsumers(ins);
michael@0 268 }
michael@0 269
michael@0 270 iter++;
michael@0 271 }
michael@0 272 // Process control flow instruction:
michael@0 273 MControlInstruction *jump = block->lastIns();
michael@0 274 jump = simplifyControlInstruction(jump);
michael@0 275
michael@0 276 // If we are pessimistic, then this will never get set.
michael@0 277 if (!jump->isInWorklist())
michael@0 278 continue;
michael@0 279 unmarkDefinition(jump);
michael@0 280 if (jump->valueNumber() == 0) {
michael@0 281 jump->setValueNumber(jump->id());
michael@0 282 for (size_t i = 0; i < jump->numSuccessors(); i++)
michael@0 283 markBlock(jump->getSuccessor(i));
michael@0 284 }
michael@0 285
michael@0 286 }
michael@0 287
michael@0 288 // If we are doing a pessimistic pass, we only go once through the
michael@0 289 // instruction list.
michael@0 290 if (pessimisticPass_)
michael@0 291 break;
michael@0 292 }
michael@0 293 #ifdef DEBUG
michael@0 294 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 295 for (MDefinitionIterator iter(*block); iter; iter++) {
michael@0 296 JS_ASSERT(!iter->isInWorklist());
michael@0 297 JS_ASSERT_IF(iter->valueNumber() == 0,
michael@0 298 !iter->hasDefUses() && (!iter->isMovable() || iter->isEffectful()));
michael@0 299 }
michael@0 300 }
michael@0 301 #endif
michael@0 302 return true;
michael@0 303 }
michael@0 304
michael@0 305 MDefinition *
michael@0 306 ValueNumberer::findDominatingDef(InstructionMap &defs, MDefinition *ins, size_t index)
michael@0 307 {
michael@0 308 JS_ASSERT(ins->valueNumber() != 0);
michael@0 309 InstructionMap::Ptr p = defs.lookup(ins->valueNumber());
michael@0 310 MDefinition *dom;
michael@0 311 if (!p || index > p->value().validUntil) {
michael@0 312 DominatingValue value;
michael@0 313 value.def = ins;
michael@0 314 // Since we are traversing the dominator tree in pre-order, when we
michael@0 315 // are looking at the |index|-th block, the next numDominated() blocks
michael@0 316 // we traverse are precisely the set of blocks that are dominated.
michael@0 317 //
michael@0 318 // So, this value is visible in all blocks if:
michael@0 319 // index <= index + ins->block->numDominated()
michael@0 320 // and becomes invalid after that.
michael@0 321 value.validUntil = index + ins->block()->numDominated();
michael@0 322
michael@0 323 if(!defs.put(ins->valueNumber(), value))
michael@0 324 return nullptr;
michael@0 325
michael@0 326 dom = ins;
michael@0 327 } else {
michael@0 328 dom = p->value().def;
michael@0 329 }
michael@0 330
michael@0 331 return dom;
michael@0 332 }
michael@0 333
michael@0 334 bool
michael@0 335 ValueNumberer::eliminateRedundancies()
michael@0 336 {
michael@0 337 // A definition is 'redundant' iff it is dominated by another definition
michael@0 338 // with the same value number.
michael@0 339 //
michael@0 340 // So, we traverse the dominator tree in pre-order, maintaining a hashmap
michael@0 341 // from value numbers to instructions.
michael@0 342 //
michael@0 343 // For each definition d with value number v, we look up v in the hashmap.
michael@0 344 //
michael@0 345 // If there is a definition d' in the hashmap, and the current traversal
michael@0 346 // index is within that instruction's dominated range, then we eliminate d,
michael@0 347 // replacing all uses of d with uses of d'.
michael@0 348 //
michael@0 349 // If there is no valid definition in the hashtable (the current definition
michael@0 350 // is not in dominated scope), then we insert the current instruction,
michael@0 351 // since it is the most dominant instruction with the given value number.
michael@0 352
michael@0 353 InstructionMap defs(alloc());
michael@0 354
michael@0 355 if (!defs.init())
michael@0 356 return false;
michael@0 357
michael@0 358 IonSpew(IonSpew_GVN, "Eliminating redundant instructions");
michael@0 359
michael@0 360 // Stack for pre-order CFG traversal.
michael@0 361 Vector<MBasicBlock *, 1, IonAllocPolicy> worklist(alloc());
michael@0 362
michael@0 363 // The index of the current block in the CFG traversal.
michael@0 364 size_t index = 0;
michael@0 365
michael@0 366 // Add all self-dominating blocks to the worklist.
michael@0 367 // This includes all roots. Order does not matter.
michael@0 368 for (MBasicBlockIterator i(graph_.begin()); i != graph_.end(); i++) {
michael@0 369 MBasicBlock *block = *i;
michael@0 370 if (block->immediateDominator() == block) {
michael@0 371 if (!worklist.append(block))
michael@0 372 return false;
michael@0 373 }
michael@0 374 }
michael@0 375
michael@0 376 // Starting from each self-dominating block, traverse the CFG in pre-order.
michael@0 377 while (!worklist.empty()) {
michael@0 378 if (mir->shouldCancel("Value Numbering (eliminate loop)"))
michael@0 379 return false;
michael@0 380 MBasicBlock *block = worklist.popCopy();
michael@0 381
michael@0 382 IonSpew(IonSpew_GVN, "Looking at block %d", block->id());
michael@0 383
michael@0 384 // Add all immediate dominators to the front of the worklist.
michael@0 385 if (!worklist.append(block->immediatelyDominatedBlocksBegin(),
michael@0 386 block->immediatelyDominatedBlocksEnd())) {
michael@0 387 return false;
michael@0 388 }
michael@0 389
michael@0 390 // For each instruction, attempt to look up a dominating definition.
michael@0 391 for (MDefinitionIterator iter(block); iter; ) {
michael@0 392 MDefinition *ins = simplify(*iter, true);
michael@0 393
michael@0 394 // Instruction was replaced, and all uses have already been fixed.
michael@0 395 if (ins != *iter) {
michael@0 396 iter = block->discardDefAt(iter);
michael@0 397 continue;
michael@0 398 }
michael@0 399
michael@0 400 // Instruction has side-effects and cannot be folded.
michael@0 401 if (!ins->isMovable() || ins->isEffectful()) {
michael@0 402 iter++;
michael@0 403 continue;
michael@0 404 }
michael@0 405
michael@0 406 MDefinition *dom = findDominatingDef(defs, ins, index);
michael@0 407 if (!dom)
michael@0 408 return false; // Insertion failed.
michael@0 409
michael@0 410 if (dom == ins || !dom->updateForReplacement(ins)) {
michael@0 411 iter++;
michael@0 412 continue;
michael@0 413 }
michael@0 414
michael@0 415 IonSpew(IonSpew_GVN, "instruction %d is dominated by instruction %d (from block %d)",
michael@0 416 ins->id(), dom->id(), dom->block()->id());
michael@0 417
michael@0 418 ins->replaceAllUsesWith(dom);
michael@0 419
michael@0 420 JS_ASSERT(!ins->hasUses());
michael@0 421 JS_ASSERT(ins->block() == block);
michael@0 422 JS_ASSERT(!ins->isEffectful());
michael@0 423 JS_ASSERT(ins->isMovable());
michael@0 424
michael@0 425 iter = ins->block()->discardDefAt(iter);
michael@0 426 }
michael@0 427 index++;
michael@0 428 }
michael@0 429
michael@0 430 JS_ASSERT(index == graph_.numBlocks());
michael@0 431 return true;
michael@0 432 }
michael@0 433
michael@0 434 // Exported method, called by the compiler.
michael@0 435 bool
michael@0 436 ValueNumberer::analyze()
michael@0 437 {
michael@0 438 return computeValueNumbers() && eliminateRedundancies();
michael@0 439 }
michael@0 440
michael@0 441 // Called by the compiler if we need to re-run GVN.
michael@0 442 bool
michael@0 443 ValueNumberer::clear()
michael@0 444 {
michael@0 445 IonSpew(IonSpew_GVN, "Clearing value numbers");
michael@0 446
michael@0 447 // Clear the VN of every MDefinition
michael@0 448 for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
michael@0 449 if (mir->shouldCancel("Value Numbering (clearing)"))
michael@0 450 return false;
michael@0 451 for (MDefinitionIterator iter(*block); iter; iter++)
michael@0 452 iter->clearValueNumberData();
michael@0 453 block->lastIns()->clearValueNumberData();
michael@0 454 }
michael@0 455
michael@0 456 return true;
michael@0 457 }
michael@0 458
michael@0 459 uint32_t
michael@0 460 MDefinition::valueNumber() const
michael@0 461 {
michael@0 462 JS_ASSERT(block_);
michael@0 463 if (valueNumber_ == nullptr)
michael@0 464 return 0;
michael@0 465 return valueNumber_->valueNumber();
michael@0 466 }
michael@0 467 void
michael@0 468 MDefinition::setValueNumber(uint32_t vn)
michael@0 469 {
michael@0 470 valueNumber_->setValueNumber(vn);
michael@0 471 }
michael@0 472 // Set the class of this to the given representative value.
michael@0 473 void
michael@0 474 ValueNumberer::setClass(MDefinition *def, MDefinition *rep)
michael@0 475 {
michael@0 476 def->valueNumberData()->setClass(def, rep);
michael@0 477 }
michael@0 478
michael@0 479 MDefinition *
michael@0 480 ValueNumberer::findSplit(MDefinition *def)
michael@0 481 {
michael@0 482 for (MDefinition *vncheck = def->valueNumberData()->classNext;
michael@0 483 vncheck != nullptr;
michael@0 484 vncheck = vncheck->valueNumberData()->classNext) {
michael@0 485 if (!def->congruentTo(vncheck)) {
michael@0 486 IonSpew(IonSpew_GVN, "Proceeding with split because %d is not congruent to %d",
michael@0 487 def->id(), vncheck->id());
michael@0 488 return vncheck;
michael@0 489 }
michael@0 490 }
michael@0 491 return nullptr;
michael@0 492 }
michael@0 493
michael@0 494 void
michael@0 495 ValueNumberer::breakClass(MDefinition *def)
michael@0 496 {
michael@0 497 if (def->valueNumber() == def->id()) {
michael@0 498 IonSpew(IonSpew_GVN, "Breaking congruence with itself: %d", def->id());
michael@0 499 ValueNumberData *defdata = def->valueNumberData();
michael@0 500 JS_ASSERT(defdata->classPrev == nullptr);
michael@0 501 // If the def was the only member of the class, then there is nothing to do.
michael@0 502 if (defdata->classNext == nullptr)
michael@0 503 return;
michael@0 504 // If upon closer inspection, we are still equivalent to this class
michael@0 505 // then there isn't anything for us to do.
michael@0 506 MDefinition *newRep = findSplit(def);
michael@0 507 if (!newRep)
michael@0 508 return;
michael@0 509 markConsumers(def);
michael@0 510 ValueNumberData *newdata = newRep->valueNumberData();
michael@0 511
michael@0 512 // Right now, |defdata| is at the front of the list, and |newdata| is
michael@0 513 // somewhere in the middle.
michael@0 514 //
michael@0 515 // We want to move |defdata| and everything up to but excluding
michael@0 516 // |newdata| to a new list, with |defdata| still as the canonical
michael@0 517 // element.
michael@0 518 //
michael@0 519 // We then want to take |newdata| and everything after, and
michael@0 520 // mark them for processing (since |newdata| is now a new canonical
michael@0 521 // element).
michael@0 522 //
michael@0 523 MDefinition *lastOld = newdata->classPrev;
michael@0 524
michael@0 525 JS_ASSERT(lastOld); // newRep is NOT the first element of the list.
michael@0 526 JS_ASSERT(lastOld->valueNumberData()->classNext == newRep);
michael@0 527
michael@0 528 //lastOld is now the last element of the old list (congruent to
michael@0 529 //|def|)
michael@0 530 lastOld->valueNumberData()->classNext = nullptr;
michael@0 531
michael@0 532 #ifdef DEBUG
michael@0 533 for (MDefinition *tmp = def; tmp != nullptr; tmp = tmp->valueNumberData()->classNext) {
michael@0 534 JS_ASSERT(tmp->valueNumber() == def->valueNumber());
michael@0 535 JS_ASSERT(tmp->congruentTo(def));
michael@0 536 JS_ASSERT(tmp != newRep);
michael@0 537 }
michael@0 538 #endif
michael@0 539 //|newRep| is now the first element of a new list, therefore it is the
michael@0 540 //new canonical element. Mark the remaining elements in the list
michael@0 541 //(including |newRep|)
michael@0 542 newdata->classPrev = nullptr;
michael@0 543 IonSpew(IonSpew_GVN, "Choosing a new representative: %d", newRep->id());
michael@0 544
michael@0 545 // make the VN of every member in the class the VN of the new representative number.
michael@0 546 for (MDefinition *tmp = newRep; tmp != nullptr; tmp = tmp->valueNumberData()->classNext) {
michael@0 547 // if this instruction is already scheduled to be processed, don't do anything.
michael@0 548 if (tmp->isInWorklist()) {
michael@0 549 IonSpew(IonSpew_GVN, "Defer to a new congruence class: %d", tmp->id());
michael@0 550 continue;
michael@0 551 }
michael@0 552 IonSpew(IonSpew_GVN, "Moving to a new congruence class: %d", tmp->id());
michael@0 553 tmp->setValueNumber(newRep->id());
michael@0 554 markConsumers(tmp);
michael@0 555 markDefinition(tmp);
michael@0 556 }
michael@0 557
michael@0 558 // Insert the new representative => number mapping into the table
michael@0 559 // Logically, there should not be anything in the table currently, but
michael@0 560 // old values are never removed, so there's a good chance something will
michael@0 561 // already be there.
michael@0 562 values.put(newRep, newRep->id());
michael@0 563 } else {
michael@0 564 // The element that is breaking from the list isn't the representative element
michael@0 565 // just strip it from the list
michael@0 566 ValueNumberData *defdata = def->valueNumberData();
michael@0 567 if (defdata->classPrev)
michael@0 568 defdata->classPrev->valueNumberData()->classNext = defdata->classNext;
michael@0 569 if (defdata->classNext)
michael@0 570 defdata->classNext->valueNumberData()->classPrev = defdata->classPrev;
michael@0 571
michael@0 572 // Make sure there is no nastinees accidentally linking elements into the old list later.
michael@0 573 defdata->classPrev = nullptr;
michael@0 574 defdata->classNext = nullptr;
michael@0 575 }
michael@0 576 }

mercurial