OLD | NEW |
1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// | 1 //===- subzero/src/IceGlobalContext.cpp - Global context defs -------------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 // translation is disabled, just dump the high-level IR and | 312 // translation is disabled, just dump the high-level IR and |
313 // continue. | 313 // continue. |
314 if (getFlags().getDisableTranslation() || | 314 if (getFlags().getDisableTranslation() || |
315 !matchSymbolName(Func->getFunctionName(), | 315 !matchSymbolName(Func->getFunctionName(), |
316 getFlags().getTranslateOnly())) { | 316 getFlags().getTranslateOnly())) { |
317 Func->dump(); | 317 Func->dump(); |
318 continue; // Func goes out of scope and gets deleted | 318 continue; // Func goes out of scope and gets deleted |
319 } | 319 } |
320 | 320 |
321 Func->translate(); | 321 Func->translate(); |
322 EmitterWorkItem *Item = nullptr; | 322 std::unique_ptr<EmitterWorkItem> Item; |
323 if (Func->hasError()) { | 323 if (Func->hasError()) { |
324 getErrorStatus()->assign(EC_Translation); | 324 getErrorStatus()->assign(EC_Translation); |
325 OstreamLocker L(this); | 325 OstreamLocker L(this); |
326 getStrError() << "ICE translation error: " << Func->getFunctionName() | 326 getStrError() << "ICE translation error: " << Func->getFunctionName() |
327 << ": " << Func->getError() << ": " | 327 << ": " << Func->getError() << ": " |
328 << Func->getFunctionNameAndSize() << "\n"; | 328 << Func->getFunctionNameAndSize() << "\n"; |
329 Item = new EmitterWorkItem(Func->getSequenceNumber()); | 329 Item = makeUnique<EmitterWorkItem>(Func->getSequenceNumber()); |
330 } else { | 330 } else { |
331 Func->getAssembler<>()->setInternal(Func->getInternal()); | 331 Func->getAssembler<>()->setInternal(Func->getInternal()); |
332 switch (getFlags().getOutFileType()) { | 332 switch (getFlags().getOutFileType()) { |
333 case FT_Elf: | 333 case FT_Elf: |
334 case FT_Iasm: { | 334 case FT_Iasm: { |
335 Func->emitIAS(); | 335 Func->emitIAS(); |
336 // The Cfg has already emitted into the assembly buffer, so | 336 // The Cfg has already emitted into the assembly buffer, so |
337 // stats have been fully collected into this thread's TLS. | 337 // stats have been fully collected into this thread's TLS. |
338 // Dump them before TLS is reset for the next Cfg. | 338 // Dump them before TLS is reset for the next Cfg. |
339 dumpStats(Func->getFunctionNameAndSize()); | 339 dumpStats(Func->getFunctionNameAndSize()); |
340 Assembler *Asm = Func->releaseAssembler(); | 340 auto Asm = Func->releaseAssembler(); |
341 // Copy relevant fields into Asm before Func is deleted. | 341 // Copy relevant fields into Asm before Func is deleted. |
342 Asm->setFunctionName(Func->getFunctionName()); | 342 Asm->setFunctionName(Func->getFunctionName()); |
343 Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); | 343 Item = makeUnique<EmitterWorkItem>(Func->getSequenceNumber(), |
| 344 std::move(Asm)); |
344 Item->setGlobalInits(Func->getGlobalInits()); | 345 Item->setGlobalInits(Func->getGlobalInits()); |
345 } break; | 346 } break; |
346 case FT_Asm: | 347 case FT_Asm: |
347 // The Cfg has not been emitted yet, so stats are not ready | 348 // The Cfg has not been emitted yet, so stats are not ready |
348 // to be dumped. | 349 // to be dumped. |
349 std::unique_ptr<VariableDeclarationList> GlobalInits = | 350 std::unique_ptr<VariableDeclarationList> GlobalInits = |
350 Func->getGlobalInits(); | 351 Func->getGlobalInits(); |
351 Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); | 352 Item = makeUnique<EmitterWorkItem>(Func->getSequenceNumber(), |
| 353 std::move(Func)); |
352 Item->setGlobalInits(std::move(GlobalInits)); | 354 Item->setGlobalInits(std::move(GlobalInits)); |
353 break; | 355 break; |
354 } | 356 } |
355 } | 357 } |
356 assert(Item); | 358 assert(Item != nullptr); |
357 emitQueueBlockingPush(Item); | 359 emitQueueBlockingPush(std::move(Item)); |
358 // The Cfg now gets deleted as Func goes out of scope. | 360 // The Cfg now gets deleted as Func goes out of scope. |
359 } | 361 } |
360 } | 362 } |
361 | 363 |
362 namespace { | 364 namespace { |
363 | 365 |
364 // Ensure Pending is large enough that Pending[Index] is valid. | 366 // Ensure Pending is large enough that Pending[Index] is valid. |
365 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { | 367 void resizePending(std::vector<std::unique_ptr<EmitterWorkItem>> *Pending, |
366 if (Index >= Pending.size()) | 368 uint32_t Index) { |
367 Utils::reserveAndResize(Pending, Index + 1); | 369 if (Index >= Pending->size()) |
| 370 Utils::reserveAndResize(*Pending, Index + 1); |
368 } | 371 } |
369 | 372 |
370 } // end of anonymous namespace | 373 } // end of anonymous namespace |
371 | 374 |
372 void GlobalContext::emitFileHeader() { | 375 void GlobalContext::emitFileHeader() { |
373 TimerMarker T1(Ice::TimerStack::TT_emitAsm, this); | 376 TimerMarker T1(Ice::TimerStack::TT_emitAsm, this); |
374 if (getFlags().getOutFileType() == FT_Elf) { | 377 if (getFlags().getOutFileType() == FT_Elf) { |
375 getObjectWriter()->writeInitialELFHeader(); | 378 getObjectWriter()->writeInitialELFHeader(); |
376 } else { | 379 } else { |
377 if (!BuildDefs::dump()) { | 380 if (!BuildDefs::dump()) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
464 } | 467 } |
465 | 468 |
466 void GlobalContext::emitItems() { | 469 void GlobalContext::emitItems() { |
467 const bool Threaded = !getFlags().isSequential(); | 470 const bool Threaded = !getFlags().isSequential(); |
468 // Pending is a vector containing the reassembled, ordered list of | 471 // Pending is a vector containing the reassembled, ordered list of |
469 // work items. When we're ready for the next item, we first check | 472 // work items. When we're ready for the next item, we first check |
470 // whether it's in the Pending list. If not, we take an item from | 473 // whether it's in the Pending list. If not, we take an item from |
471 // the work queue, and if it's not the item we're waiting for, we | 474 // the work queue, and if it's not the item we're waiting for, we |
472 // insert it into Pending and repeat. The work item is deleted | 475 // insert it into Pending and repeat. The work item is deleted |
473 // after it is processed. | 476 // after it is processed. |
474 std::vector<EmitterWorkItem *> Pending; | 477 std::vector<std::unique_ptr<EmitterWorkItem>> Pending; |
475 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); | 478 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); |
476 uint32_t ShuffleStartIndex = DesiredSequenceNumber; | 479 uint32_t ShuffleStartIndex = DesiredSequenceNumber; |
477 uint32_t ShuffleEndIndex = DesiredSequenceNumber; | 480 uint32_t ShuffleEndIndex = DesiredSequenceNumber; |
478 bool EmitQueueEmpty = false; | 481 bool EmitQueueEmpty = false; |
479 const uint32_t ShuffleWindowSize = | 482 const uint32_t ShuffleWindowSize = |
480 std::max(1u, getFlags().getReorderFunctionsWindowSize()); | 483 std::max(1u, getFlags().getReorderFunctionsWindowSize()); |
481 bool Shuffle = Threaded && getFlags().shouldReorderFunctions(); | 484 bool Shuffle = Threaded && getFlags().shouldReorderFunctions(); |
482 // Create a random number generator for function reordering. | 485 // Create a random number generator for function reordering. |
483 RandomNumberGenerator RNG(getFlags().getRandomSeed(), RPE_FunctionReordering); | 486 RandomNumberGenerator RNG(getFlags().getRandomSeed(), RPE_FunctionReordering); |
484 | 487 |
485 while (!EmitQueueEmpty) { | 488 while (!EmitQueueEmpty) { |
486 resizePending(Pending, DesiredSequenceNumber); | 489 resizePending(&Pending, DesiredSequenceNumber); |
487 // See if Pending contains DesiredSequenceNumber. | 490 // See if Pending contains DesiredSequenceNumber. |
488 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; | 491 if (Pending[DesiredSequenceNumber] == nullptr) { |
489 if (RawItem == nullptr) { | |
490 // We need to fetch an EmitterWorkItem from the queue. | 492 // We need to fetch an EmitterWorkItem from the queue. |
491 RawItem = emitQueueBlockingPop(); | 493 auto RawItem = emitQueueBlockingPop(); |
492 if (RawItem == nullptr) { | 494 if (RawItem == nullptr) { |
493 // This is the notifier for an empty queue. | 495 // This is the notifier for an empty queue. |
494 EmitQueueEmpty = true; | 496 EmitQueueEmpty = true; |
495 } else { | 497 } else { |
496 // We get an EmitterWorkItem, we need to add it to Pending. | 498 // We get an EmitterWorkItem, we need to add it to Pending. |
497 uint32_t ItemSeq = RawItem->getSequenceNumber(); | 499 uint32_t ItemSeq = RawItem->getSequenceNumber(); |
498 if (Threaded && ItemSeq != DesiredSequenceNumber) { | 500 if (Threaded && ItemSeq != DesiredSequenceNumber) { |
499 // Not the desired one, add it to Pending but do not increase | 501 // Not the desired one, add it to Pending but do not increase |
500 // DesiredSequenceNumber. Continue the loop, do not emit the item. | 502 // DesiredSequenceNumber. Continue the loop, do not emit the item. |
501 resizePending(Pending, ItemSeq); | 503 resizePending(&Pending, ItemSeq); |
502 Pending[ItemSeq] = RawItem; | 504 Pending[ItemSeq] = std::move(RawItem); |
503 continue; | 505 continue; |
504 } | 506 } |
505 // ItemSeq == DesiredSequenceNumber, we need to check if we should | 507 // ItemSeq == DesiredSequenceNumber, we need to check if we should |
506 // emit it or not. If !Threaded, we're OK with ItemSeq != | 508 // emit it or not. If !Threaded, we're OK with ItemSeq != |
507 // DesiredSequenceNumber. | 509 // DesiredSequenceNumber. |
508 Pending[DesiredSequenceNumber] = RawItem; | 510 Pending[DesiredSequenceNumber] = std::move(RawItem); |
509 } | 511 } |
510 } | 512 } |
| 513 const auto *CurrentWorkItem = Pending[DesiredSequenceNumber].get(); |
| 514 |
511 // We have the desired EmitterWorkItem or nullptr as the end notifier. | 515 // We have the desired EmitterWorkItem or nullptr as the end notifier. |
512 // If the emitter queue is not empty, increase DesiredSequenceNumber and | 516 // If the emitter queue is not empty, increase DesiredSequenceNumber and |
513 // ShuffleEndIndex. | 517 // ShuffleEndIndex. |
514 if (!EmitQueueEmpty) { | 518 if (!EmitQueueEmpty) { |
515 DesiredSequenceNumber++; | 519 DesiredSequenceNumber++; |
516 ShuffleEndIndex++; | 520 ShuffleEndIndex++; |
517 } | 521 } |
518 | 522 |
519 if (Shuffle) { | 523 if (Shuffle) { |
520 // Continue fetching EmitterWorkItem if function reordering is turned on, | 524 // Continue fetching EmitterWorkItem if function reordering is turned on, |
521 // and emit queue is not empty, and the number of consecutive pending | 525 // and emit queue is not empty, and the number of consecutive pending |
522 // items is smaller than the window size, and RawItem is not a | 526 // items is smaller than the window size, and RawItem is not a |
523 // WI_GlobalInits kind. Emit WI_GlobalInits kind block first to avoid | 527 // WI_GlobalInits kind. Emit WI_GlobalInits kind block first to avoid |
524 // holding an arbitrarily large GlobalDeclarationList. | 528 // holding an arbitrarily large GlobalDeclarationList. |
525 if (!EmitQueueEmpty && | 529 if (!EmitQueueEmpty && |
526 ShuffleEndIndex - ShuffleStartIndex < ShuffleWindowSize && | 530 ShuffleEndIndex - ShuffleStartIndex < ShuffleWindowSize && |
527 RawItem->getKind() != EmitterWorkItem::WI_GlobalInits) | 531 CurrentWorkItem->getKind() != EmitterWorkItem::WI_GlobalInits) |
528 continue; | 532 continue; |
529 | 533 |
530 // Emit the EmitterWorkItem between Pending[ShuffleStartIndex] to | 534 // Emit the EmitterWorkItem between Pending[ShuffleStartIndex] to |
531 // Pending[ShuffleEndIndex]. If function reordering turned on, shuffle the | 535 // Pending[ShuffleEndIndex]. If function reordering turned on, shuffle the |
532 // pending items from Pending[ShuffleStartIndex] to | 536 // pending items from Pending[ShuffleStartIndex] to |
533 // Pending[ShuffleEndIndex]. | 537 // Pending[ShuffleEndIndex]. |
534 RandomShuffle(Pending.begin() + ShuffleStartIndex, | 538 RandomShuffle(Pending.begin() + ShuffleStartIndex, |
535 Pending.begin() + ShuffleEndIndex, | 539 Pending.begin() + ShuffleEndIndex, |
536 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); | 540 [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); }); |
537 } | 541 } |
538 | 542 |
539 // Emit the item from ShuffleStartIndex to ShuffleEndIndex. | 543 // Emit the item from ShuffleStartIndex to ShuffleEndIndex. |
540 for (uint32_t I = ShuffleStartIndex; I < ShuffleEndIndex; I++) { | 544 for (uint32_t I = ShuffleStartIndex; I < ShuffleEndIndex; I++) { |
541 std::unique_ptr<EmitterWorkItem> Item(Pending[I]); | 545 std::unique_ptr<EmitterWorkItem> Item = std::move(Pending[I]); |
542 | 546 |
543 switch (Item->getKind()) { | 547 switch (Item->getKind()) { |
544 case EmitterWorkItem::WI_Nop: | 548 case EmitterWorkItem::WI_Nop: |
545 break; | 549 break; |
546 case EmitterWorkItem::WI_GlobalInits: { | 550 case EmitterWorkItem::WI_GlobalInits: { |
547 accumulateGlobals(Item->getGlobalInits()); | 551 accumulateGlobals(Item->getGlobalInits()); |
548 } break; | 552 } break; |
549 case EmitterWorkItem::WI_Asm: { | 553 case EmitterWorkItem::WI_Asm: { |
550 lowerGlobalsIfNoCodeHasBeenSeen(); | 554 lowerGlobalsIfNoCodeHasBeenSeen(); |
551 accumulateGlobals(Item->getGlobalInits()); | 555 accumulateGlobals(Item->getGlobalInits()); |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 } | 859 } |
856 | 860 |
857 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr at the | 861 // Note: optQueueBlockingPush and optQueueBlockingPop use unique_ptr at the |
858 // interface to take and transfer ownership, but they internally store the raw | 862 // interface to take and transfer ownership, but they internally store the raw |
859 // Cfg pointer in the work queue. This allows e.g. future queue optimizations | 863 // Cfg pointer in the work queue. This allows e.g. future queue optimizations |
860 // such as the use of atomics to modify queue elements. | 864 // such as the use of atomics to modify queue elements. |
861 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { | 865 void GlobalContext::optQueueBlockingPush(std::unique_ptr<Cfg> Func) { |
862 assert(Func); | 866 assert(Func); |
863 { | 867 { |
864 TimerMarker _(TimerStack::TT_qTransPush, this); | 868 TimerMarker _(TimerStack::TT_qTransPush, this); |
865 OptQ.blockingPush(Func.release()); | 869 OptQ.blockingPush(std::move(Func)); |
866 } | 870 } |
867 if (getFlags().isSequential()) | 871 if (getFlags().isSequential()) |
868 translateFunctions(); | 872 translateFunctions(); |
869 } | 873 } |
870 | 874 |
871 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { | 875 std::unique_ptr<Cfg> GlobalContext::optQueueBlockingPop() { |
872 TimerMarker _(TimerStack::TT_qTransPop, this); | 876 TimerMarker _(TimerStack::TT_qTransPop, this); |
873 return std::unique_ptr<Cfg>(OptQ.blockingPop()); | 877 return std::unique_ptr<Cfg>(OptQ.blockingPop()); |
874 } | 878 } |
875 | 879 |
876 void GlobalContext::emitQueueBlockingPush(EmitterWorkItem *Item) { | 880 void GlobalContext::emitQueueBlockingPush( |
| 881 std::unique_ptr<EmitterWorkItem> Item) { |
877 assert(Item); | 882 assert(Item); |
878 { | 883 { |
879 TimerMarker _(TimerStack::TT_qEmitPush, this); | 884 TimerMarker _(TimerStack::TT_qEmitPush, this); |
880 EmitQ.blockingPush(Item); | 885 EmitQ.blockingPush(std::move(Item)); |
881 } | 886 } |
882 if (getFlags().isSequential()) | 887 if (getFlags().isSequential()) |
883 emitItems(); | 888 emitItems(); |
884 } | 889 } |
885 | 890 |
886 EmitterWorkItem *GlobalContext::emitQueueBlockingPop() { | 891 std::unique_ptr<EmitterWorkItem> GlobalContext::emitQueueBlockingPop() { |
887 TimerMarker _(TimerStack::TT_qEmitPop, this); | 892 TimerMarker _(TimerStack::TT_qEmitPop, this); |
888 return EmitQ.blockingPop(); | 893 return EmitQ.blockingPop(); |
889 } | 894 } |
890 | 895 |
891 void GlobalContext::dumpStats(const IceString &Name, bool Final) { | 896 void GlobalContext::dumpStats(const IceString &Name, bool Final) { |
892 if (!getFlags().getDumpStats()) | 897 if (!getFlags().getDumpStats()) |
893 return; | 898 return; |
894 if (Final) { | 899 if (Final) { |
895 getStatsCumulative()->dump(Name, this); | 900 getStatsCumulative()->dump(Name, this); |
896 } else { | 901 } else { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 Ctx = Func->getContext(); | 943 Ctx = Func->getContext(); |
939 Active = | 944 Active = |
940 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); | 945 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
941 if (Active) | 946 if (Active) |
942 Ctx->pushTimer(ID, StackID); | 947 Ctx->pushTimer(ID, StackID); |
943 } | 948 } |
944 | 949 |
945 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); | 950 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
946 | 951 |
947 } // end of namespace Ice | 952 } // end of namespace Ice |
OLD | NEW |