decode_impl.hh revision 8737
1/* 2 * Copyright (c) 2004-2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Kevin Lim 29 */ 30 31#include "arch/types.hh" 32#include "base/trace.hh" 33#include "config/full_system.hh" 34#include "config/the_isa.hh" 35#include "cpu/o3/decode.hh" 36#include "cpu/inst_seq.hh" 37#include "debug/Activity.hh" 38#include "debug/Decode.hh" 39#include "params/DerivO3CPU.hh" 40 41// clang complains about std::set being overloaded with Packet::set if 42// we open up the entire namespace std 43using std::list; 44 45template<class Impl> 46DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params) 47 : cpu(_cpu), 48 renameToDecodeDelay(params->renameToDecodeDelay), 49 iewToDecodeDelay(params->iewToDecodeDelay), 50 commitToDecodeDelay(params->commitToDecodeDelay), 51 fetchToDecodeDelay(params->fetchToDecodeDelay), 52 decodeWidth(params->decodeWidth), 53 numThreads(params->numThreads) 54{ 55 _status = Inactive; 56 57 // Setup status, make sure stall signals are clear. 58 for (ThreadID tid = 0; tid < numThreads; ++tid) { 59 decodeStatus[tid] = Idle; 60 61 stalls[tid].rename = false; 62 stalls[tid].iew = false; 63 stalls[tid].commit = false; 64 } 65 66 // @todo: Make into a parameter 67 skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth; 68} 69 70template <class Impl> 71std::string 72DefaultDecode<Impl>::name() const 73{ 74 return cpu->name() + ".decode"; 75} 76 77template <class Impl> 78void 79DefaultDecode<Impl>::regStats() 80{ 81 decodeIdleCycles 82 .name(name() + ".IdleCycles") 83 .desc("Number of cycles decode is idle") 84 .prereq(decodeIdleCycles); 85 decodeBlockedCycles 86 .name(name() + ".BlockedCycles") 87 .desc("Number of cycles decode is blocked") 88 .prereq(decodeBlockedCycles); 89 decodeRunCycles 90 .name(name() + ".RunCycles") 91 .desc("Number of cycles decode is running") 92 .prereq(decodeRunCycles); 93 decodeUnblockCycles 94 .name(name() + ".UnblockCycles") 95 .desc("Number of cycles decode is unblocking") 96 .prereq(decodeUnblockCycles); 97 decodeSquashCycles 98 .name(name() + ".SquashCycles") 99 .desc("Number of cycles decode is squashing") 100 .prereq(decodeSquashCycles); 101 decodeBranchResolved 102 .name(name() + ".BranchResolved") 103 .desc("Number of times decode resolved a branch") 104 .prereq(decodeBranchResolved); 105 decodeBranchMispred 106 .name(name() + ".BranchMispred") 107 .desc("Number of times decode detected a branch misprediction") 108 .prereq(decodeBranchMispred); 109 decodeControlMispred 110 .name(name() + ".ControlMispred") 111 .desc("Number of times decode detected an instruction incorrectly" 112 " predicted as a control") 113 .prereq(decodeControlMispred); 114 decodeDecodedInsts 115 .name(name() + ".DecodedInsts") 116 .desc("Number of instructions handled by decode") 117 .prereq(decodeDecodedInsts); 118 decodeSquashedInsts 119 .name(name() + ".SquashedInsts") 120 .desc("Number of squashed instructions handled by decode") 121 .prereq(decodeSquashedInsts); 122} 123 124template<class Impl> 125void 126DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr) 127{ 128 timeBuffer = tb_ptr; 129 130 // Setup wire to write information back to fetch. 131 toFetch = timeBuffer->getWire(0); 132 133 // Create wires to get information from proper places in time buffer. 134 fromRename = timeBuffer->getWire(-renameToDecodeDelay); 135 fromIEW = timeBuffer->getWire(-iewToDecodeDelay); 136 fromCommit = timeBuffer->getWire(-commitToDecodeDelay); 137} 138 139template<class Impl> 140void 141DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr) 142{ 143 decodeQueue = dq_ptr; 144 145 // Setup wire to write information to proper place in decode queue. 146 toRename = decodeQueue->getWire(0); 147} 148 149template<class Impl> 150void 151DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr) 152{ 153 fetchQueue = fq_ptr; 154 155 // Setup wire to read information from fetch queue. 156 fromFetch = fetchQueue->getWire(-fetchToDecodeDelay); 157} 158 159template<class Impl> 160void 161DefaultDecode<Impl>::setActiveThreads(std::list<ThreadID> *at_ptr) 162{ 163 activeThreads = at_ptr; 164} 165 166template <class Impl> 167bool 168DefaultDecode<Impl>::drain() 169{ 170 // Decode is done draining at any time. 171 cpu->signalDrained(); 172 return true; 173} 174 175template <class Impl> 176void 177DefaultDecode<Impl>::takeOverFrom() 178{ 179 _status = Inactive; 180 181 // Be sure to reset state and clear out any old instructions. 182 for (ThreadID tid = 0; tid < numThreads; ++tid) { 183 decodeStatus[tid] = Idle; 184 185 stalls[tid].rename = false; 186 stalls[tid].iew = false; 187 stalls[tid].commit = false; 188 while (!insts[tid].empty()) 189 insts[tid].pop(); 190 while (!skidBuffer[tid].empty()) 191 skidBuffer[tid].pop(); 192 branchCount[tid] = 0; 193 } 194 wroteToTimeBuffer = false; 195} 196 197template<class Impl> 198bool 199DefaultDecode<Impl>::checkStall(ThreadID tid) const 200{ 201 bool ret_val = false; 202 203 if (stalls[tid].rename) { 204 DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid); 205 ret_val = true; 206 } else if (stalls[tid].iew) { 207 DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid); 208 ret_val = true; 209 } else if (stalls[tid].commit) { 210 DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid); 211 ret_val = true; 212 } 213 214 return ret_val; 215} 216 217template<class Impl> 218inline bool 219DefaultDecode<Impl>::fetchInstsValid() 220{ 221 return fromFetch->size > 0; 222} 223 224template<class Impl> 225bool 226DefaultDecode<Impl>::block(ThreadID tid) 227{ 228 DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid); 229 230 // Add the current inputs to the skid buffer so they can be 231 // reprocessed when this stage unblocks. 232 skidInsert(tid); 233 234 // If the decode status is blocked or unblocking then decode has not yet 235 // signalled fetch to unblock. In that case, there is no need to tell 236 // fetch to block. 237 if (decodeStatus[tid] != Blocked) { 238 // Set the status to Blocked. 239 decodeStatus[tid] = Blocked; 240 241 if (decodeStatus[tid] != Unblocking) { 242 toFetch->decodeBlock[tid] = true; 243 wroteToTimeBuffer = true; 244 } 245 246 return true; 247 } 248 249 return false; 250} 251 252template<class Impl> 253bool 254DefaultDecode<Impl>::unblock(ThreadID tid) 255{ 256 // Decode is done unblocking only if the skid buffer is empty. 257 if (skidBuffer[tid].empty()) { 258 DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid); 259 toFetch->decodeUnblock[tid] = true; 260 wroteToTimeBuffer = true; 261 262 decodeStatus[tid] = Running; 263 return true; 264 } 265 266 DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid); 267 268 return false; 269} 270 271template<class Impl> 272void 273DefaultDecode<Impl>::squash(DynInstPtr &inst, ThreadID tid) 274{ 275 DPRINTF(Decode, "[tid:%i]: [sn:%i] Squashing due to incorrect branch " 276 "prediction detected at decode.\n", tid, inst->seqNum); 277 278 // Send back mispredict information. 279 toFetch->decodeInfo[tid].branchMispredict = true; 280 toFetch->decodeInfo[tid].predIncorrect = true; 281 toFetch->decodeInfo[tid].squash = true; 282 toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum; 283 toFetch->decodeInfo[tid].nextPC = inst->branchTarget(); 284 toFetch->decodeInfo[tid].branchTaken = inst->pcState().branching(); 285 toFetch->decodeInfo[tid].squashInst = inst; 286 287 InstSeqNum squash_seq_num = inst->seqNum; 288 289 // Might have to tell fetch to unblock. 290 if (decodeStatus[tid] == Blocked || 291 decodeStatus[tid] == Unblocking) { 292 toFetch->decodeUnblock[tid] = 1; 293 } 294 295 // Set status to squashing. 296 decodeStatus[tid] = Squashing; 297 298 for (int i=0; i<fromFetch->size; i++) { 299 if (fromFetch->insts[i]->threadNumber == tid && 300 fromFetch->insts[i]->seqNum > squash_seq_num) { 301 fromFetch->insts[i]->setSquashed(); 302 } 303 } 304 305 // Clear the instruction list and skid buffer in case they have any 306 // insts in them. 307 while (!insts[tid].empty()) { 308 insts[tid].pop(); 309 } 310 311 while (!skidBuffer[tid].empty()) { 312 skidBuffer[tid].pop(); 313 } 314 315 // Squash instructions up until this one 316 cpu->removeInstsUntil(squash_seq_num, tid); 317} 318 319template<class Impl> 320unsigned 321DefaultDecode<Impl>::squash(ThreadID tid) 322{ 323 DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid); 324 325 if (decodeStatus[tid] == Blocked || 326 decodeStatus[tid] == Unblocking) { 327#if !FULL_SYSTEM 328 // In syscall emulation, we can have both a block and a squash due 329 // to a syscall in the same cycle. This would cause both signals to 330 // be high. This shouldn't happen in full system. 331 // @todo: Determine if this still happens. 332 if (toFetch->decodeBlock[tid]) { 333 toFetch->decodeBlock[tid] = 0; 334 } else { 335 toFetch->decodeUnblock[tid] = 1; 336 } 337#else 338 toFetch->decodeUnblock[tid] = 1; 339#endif 340 } 341 342 // Set status to squashing. 343 decodeStatus[tid] = Squashing; 344 345 // Go through incoming instructions from fetch and squash them. 346 unsigned squash_count = 0; 347 348 for (int i=0; i<fromFetch->size; i++) { 349 if (fromFetch->insts[i]->threadNumber == tid) { 350 fromFetch->insts[i]->setSquashed(); 351 squash_count++; 352 } 353 } 354 355 // Clear the instruction list and skid buffer in case they have any 356 // insts in them. 357 while (!insts[tid].empty()) { 358 insts[tid].pop(); 359 } 360 361 while (!skidBuffer[tid].empty()) { 362 skidBuffer[tid].pop(); 363 } 364 365 return squash_count; 366} 367 368template<class Impl> 369void 370DefaultDecode<Impl>::skidInsert(ThreadID tid) 371{ 372 DynInstPtr inst = NULL; 373 374 while (!insts[tid].empty()) { 375 inst = insts[tid].front(); 376 377 insts[tid].pop(); 378 379 assert(tid == inst->threadNumber); 380 381 DPRINTF(Decode,"Inserting [sn:%lli] PC: %s into decode skidBuffer %i\n", 382 inst->seqNum, inst->pcState(), inst->threadNumber); 383 384 skidBuffer[tid].push(inst); 385 } 386 387 // @todo: Eventually need to enforce this by not letting a thread 388 // fetch past its skidbuffer 389 assert(skidBuffer[tid].size() <= skidBufferMax); 390} 391 392template<class Impl> 393bool 394DefaultDecode<Impl>::skidsEmpty() 395{ 396 list<ThreadID>::iterator threads = activeThreads->begin(); 397 list<ThreadID>::iterator end = activeThreads->end(); 398 399 while (threads != end) { 400 ThreadID tid = *threads++; 401 if (!skidBuffer[tid].empty()) 402 return false; 403 } 404 405 return true; 406} 407 408template<class Impl> 409void 410DefaultDecode<Impl>::updateStatus() 411{ 412 bool any_unblocking = false; 413 414 list<ThreadID>::iterator threads = activeThreads->begin(); 415 list<ThreadID>::iterator end = activeThreads->end(); 416 417 while (threads != end) { 418 ThreadID tid = *threads++; 419 420 if (decodeStatus[tid] == Unblocking) { 421 any_unblocking = true; 422 break; 423 } 424 } 425 426 // Decode will have activity if it's unblocking. 427 if (any_unblocking) { 428 if (_status == Inactive) { 429 _status = Active; 430 431 DPRINTF(Activity, "Activating stage.\n"); 432 433 cpu->activateStage(O3CPU::DecodeIdx); 434 } 435 } else { 436 // If it's not unblocking, then decode will not have any internal 437 // activity. Switch it to inactive. 438 if (_status == Active) { 439 _status = Inactive; 440 DPRINTF(Activity, "Deactivating stage.\n"); 441 442 cpu->deactivateStage(O3CPU::DecodeIdx); 443 } 444 } 445} 446 447template <class Impl> 448void 449DefaultDecode<Impl>::sortInsts() 450{ 451 int insts_from_fetch = fromFetch->size; 452 for (int i = 0; i < insts_from_fetch; ++i) { 453 insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]); 454 } 455} 456 457template<class Impl> 458void 459DefaultDecode<Impl>::readStallSignals(ThreadID tid) 460{ 461 if (fromRename->renameBlock[tid]) { 462 stalls[tid].rename = true; 463 } 464 465 if (fromRename->renameUnblock[tid]) { 466 assert(stalls[tid].rename); 467 stalls[tid].rename = false; 468 } 469 470 if (fromIEW->iewBlock[tid]) { 471 stalls[tid].iew = true; 472 } 473 474 if (fromIEW->iewUnblock[tid]) { 475 assert(stalls[tid].iew); 476 stalls[tid].iew = false; 477 } 478 479 if (fromCommit->commitBlock[tid]) { 480 stalls[tid].commit = true; 481 } 482 483 if (fromCommit->commitUnblock[tid]) { 484 assert(stalls[tid].commit); 485 stalls[tid].commit = false; 486 } 487} 488 489template <class Impl> 490bool 491DefaultDecode<Impl>::checkSignalsAndUpdate(ThreadID tid) 492{ 493 // Check if there's a squash signal, squash if there is. 494 // Check stall signals, block if necessary. 495 // If status was blocked 496 // Check if stall conditions have passed 497 // if so then go to unblocking 498 // If status was Squashing 499 // check if squashing is not high. Switch to running this cycle. 500 501 // Update the per thread stall statuses. 502 readStallSignals(tid); 503 504 // Check squash signals from commit. 505 if (fromCommit->commitInfo[tid].squash) { 506 507 DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash " 508 "from commit.\n", tid); 509 510 squash(tid); 511 512 return true; 513 } 514 515 // Check ROB squash signals from commit. 516 if (fromCommit->commitInfo[tid].robSquashing) { 517 DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid); 518 519 // Continue to squash. 520 decodeStatus[tid] = Squashing; 521 522 return true; 523 } 524 525 if (checkStall(tid)) { 526 return block(tid); 527 } 528 529 if (decodeStatus[tid] == Blocked) { 530 DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n", 531 tid); 532 533 decodeStatus[tid] = Unblocking; 534 535 unblock(tid); 536 537 return true; 538 } 539 540 if (decodeStatus[tid] == Squashing) { 541 // Switch status to running if decode isn't being told to block or 542 // squash this cycle. 543 DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n", 544 tid); 545 546 decodeStatus[tid] = Running; 547 548 return false; 549 } 550 551 // If we've reached this point, we have not gotten any signals that 552 // cause decode to change its status. Decode remains the same as before. 553 return false; 554} 555 556template<class Impl> 557void 558DefaultDecode<Impl>::tick() 559{ 560 wroteToTimeBuffer = false; 561 562 bool status_change = false; 563 564 toRenameIndex = 0; 565 566 list<ThreadID>::iterator threads = activeThreads->begin(); 567 list<ThreadID>::iterator end = activeThreads->end(); 568 569 sortInsts(); 570 571 //Check stall and squash signals. 572 while (threads != end) { 573 ThreadID tid = *threads++; 574 575 DPRINTF(Decode,"Processing [tid:%i]\n",tid); 576 status_change = checkSignalsAndUpdate(tid) || status_change; 577 578 decode(status_change, tid); 579 } 580 581 if (status_change) { 582 updateStatus(); 583 } 584 585 if (wroteToTimeBuffer) { 586 DPRINTF(Activity, "Activity this cycle.\n"); 587 588 cpu->activityThisCycle(); 589 } 590} 591 592template<class Impl> 593void 594DefaultDecode<Impl>::decode(bool &status_change, ThreadID tid) 595{ 596 // If status is Running or idle, 597 // call decodeInsts() 598 // If status is Unblocking, 599 // buffer any instructions coming from fetch 600 // continue trying to empty skid buffer 601 // check if stall conditions have passed 602 603 if (decodeStatus[tid] == Blocked) { 604 ++decodeBlockedCycles; 605 } else if (decodeStatus[tid] == Squashing) { 606 ++decodeSquashCycles; 607 } 608 609 // Decode should try to decode as many instructions as its bandwidth 610 // will allow, as long as it is not currently blocked. 611 if (decodeStatus[tid] == Running || 612 decodeStatus[tid] == Idle) { 613 DPRINTF(Decode, "[tid:%u]: Not blocked, so attempting to run " 614 "stage.\n",tid); 615 616 decodeInsts(tid); 617 } else if (decodeStatus[tid] == Unblocking) { 618 // Make sure that the skid buffer has something in it if the 619 // status is unblocking. 620 assert(!skidsEmpty()); 621 622 // If the status was unblocking, then instructions from the skid 623 // buffer were used. Remove those instructions and handle 624 // the rest of unblocking. 625 decodeInsts(tid); 626 627 if (fetchInstsValid()) { 628 // Add the current inputs to the skid buffer so they can be 629 // reprocessed when this stage unblocks. 630 skidInsert(tid); 631 } 632 633 status_change = unblock(tid) || status_change; 634 } 635} 636 637template <class Impl> 638void 639DefaultDecode<Impl>::decodeInsts(ThreadID tid) 640{ 641 // Instructions can come either from the skid buffer or the list of 642 // instructions coming from fetch, depending on decode's status. 643 int insts_available = decodeStatus[tid] == Unblocking ? 644 skidBuffer[tid].size() : insts[tid].size(); 645 646 if (insts_available == 0) { 647 DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out" 648 " early.\n",tid); 649 // Should I change the status to idle? 650 ++decodeIdleCycles; 651 return; 652 } else if (decodeStatus[tid] == Unblocking) { 653 DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid " 654 "buffer.\n",tid); 655 ++decodeUnblockCycles; 656 } else if (decodeStatus[tid] == Running) { 657 ++decodeRunCycles; 658 } 659 660 DynInstPtr inst; 661 662 std::queue<DynInstPtr> 663 &insts_to_decode = decodeStatus[tid] == Unblocking ? 664 skidBuffer[tid] : insts[tid]; 665 666 DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid); 667 668 while (insts_available > 0 && toRenameIndex < decodeWidth) { 669 assert(!insts_to_decode.empty()); 670 671 inst = insts_to_decode.front(); 672 673 insts_to_decode.pop(); 674 675 DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with " 676 "PC %s\n", tid, inst->seqNum, inst->pcState()); 677 678 if (inst->isSquashed()) { 679 DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %s is " 680 "squashed, skipping.\n", 681 tid, inst->seqNum, inst->pcState()); 682 683 ++decodeSquashedInsts; 684 685 --insts_available; 686 687 continue; 688 } 689 690 // Also check if instructions have no source registers. Mark 691 // them as ready to issue at any time. Not sure if this check 692 // should exist here or at a later stage; however it doesn't matter 693 // too much for function correctness. 694 if (inst->numSrcRegs() == 0) { 695 inst->setCanIssue(); 696 } 697 698 // This current instruction is valid, so add it into the decode 699 // queue. The next instruction may not be valid, so check to 700 // see if branches were predicted correctly. 701 toRename->insts[toRenameIndex] = inst; 702 703 ++(toRename->size); 704 ++toRenameIndex; 705 ++decodeDecodedInsts; 706 --insts_available; 707 708#if TRACING_ON 709 inst->decodeTick = curTick(); 710#endif 711 712 // Ensure that if it was predicted as a branch, it really is a 713 // branch. 714 if (inst->readPredTaken() && !inst->isControl()) { 715 panic("Instruction predicted as a branch!"); 716 717 ++decodeControlMispred; 718 719 // Might want to set some sort of boolean and just do 720 // a check at the end 721 squash(inst, inst->threadNumber); 722 723 break; 724 } 725 726 // Go ahead and compute any PC-relative branches. 727 if (inst->isDirectCtrl() && inst->isUncondCtrl()) { 728 ++decodeBranchResolved; 729 730 if (!(inst->branchTarget() == inst->readPredTarg())) { 731 ++decodeBranchMispred; 732 733 // Might want to set some sort of boolean and just do 734 // a check at the end 735 squash(inst, inst->threadNumber); 736 TheISA::PCState target = inst->branchTarget(); 737 738 DPRINTF(Decode, "[sn:%i]: Updating predictions: PredPC: %s\n", 739 inst->seqNum, target); 740 //The micro pc after an instruction level branch should be 0 741 inst->setPredTarg(target); 742 break; 743 } 744 } 745 } 746 747 // If we didn't process all instructions, then we will need to block 748 // and put all those instructions into the skid buffer. 749 if (!insts_to_decode.empty()) { 750 block(tid); 751 } 752 753 // Record that decode has written to the time buffer for activity 754 // tracking. 755 if (toRenameIndex) { 756 wroteToTimeBuffer = true; 757 } 758} 759