| 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 // This file defines aspects of the compilation that persist across | 10 // This file defines aspects of the compilation that persist across |
| 11 // multiple functions. | 11 // multiple functions. |
| 12 // | 12 // |
| 13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
| 14 | 14 |
| 15 #include <ctype.h> // isdigit(), isupper() | 15 #include <ctype.h> // isdigit(), isupper() |
| 16 #include <locale> // locale | 16 #include <locale> // locale |
| 17 #include <unordered_map> | 17 #include <unordered_map> |
| 18 | 18 |
| 19 #include "llvm/Support/Timer.h" | 19 #include "llvm/Support/Timer.h" |
| 20 | 20 |
| 21 #include "IceCfg.h" | 21 #include "IceCfg.h" |
| 22 #include "IceCfgNode.h" |
| 22 #include "IceClFlags.h" | 23 #include "IceClFlags.h" |
| 23 #include "IceDefs.h" | 24 #include "IceDefs.h" |
| 24 #include "IceELFObjectWriter.h" | 25 #include "IceELFObjectWriter.h" |
| 25 #include "IceGlobalContext.h" | 26 #include "IceGlobalContext.h" |
| 26 #include "IceGlobalInits.h" | 27 #include "IceGlobalInits.h" |
| 27 #include "IceOperand.h" | 28 #include "IceOperand.h" |
| 28 #include "IceTargetLowering.h" | 29 #include "IceTargetLowering.h" |
| 29 #include "IceTimerTree.h" | 30 #include "IceTimerTree.h" |
| 30 #include "IceTypes.h" | 31 #include "IceTypes.h" |
| 31 | 32 |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 // current function matches the -translate-only option. If | 271 // current function matches the -translate-only option. If |
| 271 // translation is disabled, just dump the high-level IR and | 272 // translation is disabled, just dump the high-level IR and |
| 272 // continue. | 273 // continue. |
| 273 if (getFlags().getDisableTranslation() || | 274 if (getFlags().getDisableTranslation() || |
| 274 !matchSymbolName(Func->getFunctionName(), | 275 !matchSymbolName(Func->getFunctionName(), |
| 275 getFlags().getTranslateOnly())) { | 276 getFlags().getTranslateOnly())) { |
| 276 Func->dump(); | 277 Func->dump(); |
| 277 Cfg::setCurrentCfg(nullptr); | 278 Cfg::setCurrentCfg(nullptr); |
| 278 continue; // Func goes out of scope and gets deleted | 279 continue; // Func goes out of scope and gets deleted |
| 279 } | 280 } |
| 281 |
| 280 Func->translate(); | 282 Func->translate(); |
| 281 EmitterWorkItem *Item = nullptr; | 283 EmitterWorkItem *Item = nullptr; |
| 282 if (Func->hasError()) { | 284 if (Func->hasError()) { |
| 283 getErrorStatus()->assign(EC_Translation); | 285 getErrorStatus()->assign(EC_Translation); |
| 284 OstreamLocker L(this); | 286 OstreamLocker L(this); |
| 285 getStrError() << "ICE translation error: " << Func->getFunctionName() | 287 getStrError() << "ICE translation error: " << Func->getFunctionName() |
| 286 << ": " << Func->getError() << "\n"; | 288 << ": " << Func->getError() << "\n"; |
| 287 Item = new EmitterWorkItem(Func->getSequenceNumber()); | 289 Item = new EmitterWorkItem(Func->getSequenceNumber()); |
| 290 Item->setGlobalInits(Func->getGlobalInits()); |
| 288 } else { | 291 } else { |
| 289 Func->getAssembler<>()->setInternal(Func->getInternal()); | 292 Func->getAssembler<>()->setInternal(Func->getInternal()); |
| 290 switch (getFlags().getOutFileType()) { | 293 switch (getFlags().getOutFileType()) { |
| 291 case FT_Elf: | 294 case FT_Elf: |
| 292 case FT_Iasm: { | 295 case FT_Iasm: { |
| 293 Func->emitIAS(); | 296 Func->emitIAS(); |
| 294 // The Cfg has already emitted into the assembly buffer, so | 297 // The Cfg has already emitted into the assembly buffer, so |
| 295 // stats have been fully collected into this thread's TLS. | 298 // stats have been fully collected into this thread's TLS. |
| 296 // Dump them before TLS is reset for the next Cfg. | 299 // Dump them before TLS is reset for the next Cfg. |
| 297 dumpStats(Func->getFunctionName()); | 300 dumpStats(Func->getFunctionName()); |
| 298 Assembler *Asm = Func->releaseAssembler(); | 301 Assembler *Asm = Func->releaseAssembler(); |
| 299 // Copy relevant fields into Asm before Func is deleted. | 302 // Copy relevant fields into Asm before Func is deleted. |
| 300 Asm->setFunctionName(Func->getFunctionName()); | 303 Asm->setFunctionName(Func->getFunctionName()); |
| 301 Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); | 304 Item = new EmitterWorkItem(Func->getSequenceNumber(), Asm); |
| 305 Item->setGlobalInits(Func->getGlobalInits()); |
| 302 } break; | 306 } break; |
| 303 case FT_Asm: | 307 case FT_Asm: |
| 304 // The Cfg has not been emitted yet, so stats are not ready | 308 // The Cfg has not been emitted yet, so stats are not ready |
| 305 // to be dumped. | 309 // to be dumped. |
| 310 std::unique_ptr<VariableDeclarationList> GlobalInits = |
| 311 Func->getGlobalInits(); |
| 306 Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); | 312 Item = new EmitterWorkItem(Func->getSequenceNumber(), Func.release()); |
| 313 Item->setGlobalInits(std::move(GlobalInits)); |
| 307 break; | 314 break; |
| 308 } | 315 } |
| 309 } | 316 } |
| 310 Cfg::setCurrentCfg(nullptr); | 317 Cfg::setCurrentCfg(nullptr); |
| 311 assert(Item); | 318 assert(Item); |
| 312 emitQueueBlockingPush(Item); | 319 emitQueueBlockingPush(Item); |
| 313 // The Cfg now gets deleted as Func goes out of scope. | 320 // The Cfg now gets deleted as Func goes out of scope. |
| 314 } | 321 } |
| 315 } | 322 } |
| 316 | 323 |
| 317 namespace { | 324 namespace { |
| 318 | 325 |
| 326 // Adds an array of pointers to all the profiler-generated globals. The |
| 327 // __Sz_profile_summary function iterates over this array for printing the |
| 328 // profiling counters. |
| 329 VariableDeclaration *blockProfileInfo(const VariableDeclarationList &Globals) { |
| 330 auto *Var = VariableDeclaration::create(); |
| 331 Var->setAlignment(typeWidthInBytes(IceType_i64)); |
| 332 Var->setIsConstant(true); |
| 333 |
| 334 // Note: if you change this symbol, make sure to update |
| 335 // runtime/szrt_profiler.c as well. |
| 336 Var->setName("__Sz_block_profile_info"); |
| 337 Var->setLinkage(llvm::GlobalValue::ExternalLinkage); |
| 338 for (const VariableDeclaration *Global : Globals) { |
| 339 if (Cfg::isProfileGlobal(*Global)) { |
| 340 constexpr RelocOffsetT BlockExecutionCounterOffset = 0; |
| 341 Var->addInitializer(new VariableDeclaration::RelocInitializer( |
| 342 Global, BlockExecutionCounterOffset)); |
| 343 } |
| 344 } |
| 345 |
| 346 // This adds a 64-bit sentinel entry to the end of our array. For 32-bit |
| 347 // architectures this will waste 4 bytes. |
| 348 const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64); |
| 349 Var->addInitializer( |
| 350 new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr)); |
| 351 |
| 352 return Var; |
| 353 } |
| 354 |
| 355 void addBlockProfileInfoArrayToGlobals(VariableDeclarationList *Globals) { |
| 356 // Purposefully create the Var temp to prevent bugs in case the compiler |
| 357 // reorders instructions in a way that Globals is extended before the call |
| 358 // to profileInfoArray. |
| 359 VariableDeclaration *Var = blockProfileInfo(*Globals); |
| 360 Globals->push_back(Var); |
| 361 } |
| 362 |
| 319 void lowerGlobals(GlobalContext *Ctx, | 363 void lowerGlobals(GlobalContext *Ctx, |
| 320 std::unique_ptr<VariableDeclarationList> VariableDeclarations, | 364 std::unique_ptr<VariableDeclarationList> VariableDeclarations, |
| 321 TargetDataLowering *DataLowering) { | 365 TargetDataLowering *DataLowering) { |
| 322 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); | 366 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); |
| 323 const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() && | 367 const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() && |
| 324 Ctx->getFlags().getVerboseFocusOn().empty(); | 368 Ctx->getFlags().getVerboseFocusOn().empty(); |
| 325 if (DumpGlobalVariables) { | 369 if (DumpGlobalVariables) { |
| 326 OstreamLocker L(Ctx); | 370 OstreamLocker L(Ctx); |
| 327 Ostream &Stream = Ctx->getStrDump(); | 371 Ostream &Stream = Ctx->getStrDump(); |
| 328 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { | 372 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { |
| 329 Global->dump(Ctx, Stream); | 373 Global->dump(Ctx, Stream); |
| 330 } | 374 } |
| 331 } | 375 } |
| 332 if (Ctx->getFlags().getDisableTranslation()) | 376 if (Ctx->getFlags().getDisableTranslation()) |
| 333 return; | 377 return; |
| 378 |
| 379 // There should be no need to emit the block_profile_info array if profiling |
| 380 // is disabled. In practice, given that szrt_profiler.o will always be |
| 381 // embedded in the application, we need to add it. In a non-profiled build |
| 382 // this array will only contain the nullptr terminator. |
| 383 addBlockProfileInfoArrayToGlobals(VariableDeclarations.get()); |
| 384 |
| 334 DataLowering->lowerGlobals(std::move(VariableDeclarations)); | 385 DataLowering->lowerGlobals(std::move(VariableDeclarations)); |
| 335 } | 386 } |
| 336 | 387 |
| 337 // Ensure Pending is large enough that Pending[Index] is valid. | 388 // Ensure Pending is large enough that Pending[Index] is valid. |
| 338 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { | 389 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { |
| 339 if (Index >= Pending.size()) | 390 if (Index >= Pending.size()) |
| 340 Pending.resize(Index + 1); | 391 Pending.resize(Index + 1); |
| 341 } | 392 } |
| 342 | 393 |
| 394 void addAllIfNotNull(std::unique_ptr<VariableDeclarationList> src, |
| 395 VariableDeclarationList *dst) { |
| 396 if (src != nullptr) { |
| 397 dst->insert(dst->end(), src->begin(), src->end()); |
| 398 } |
| 399 } |
| 400 |
| 343 } // end of anonymous namespace | 401 } // end of anonymous namespace |
| 344 | 402 |
| 345 void GlobalContext::emitItems() { | 403 void GlobalContext::emitItems() { |
| 346 const bool Threaded = !getFlags().isSequential(); | 404 const bool Threaded = !getFlags().isSequential(); |
| 347 // Pending is a vector containing the reassembled, ordered list of | 405 // Pending is a vector containing the reassembled, ordered list of |
| 348 // work items. When we're ready for the next item, we first check | 406 // work items. When we're ready for the next item, we first check |
| 349 // whether it's in the Pending list. If not, we take an item from | 407 // whether it's in the Pending list. If not, we take an item from |
| 350 // the work queue, and if it's not the item we're waiting for, we | 408 // the work queue, and if it's not the item we're waiting for, we |
| 351 // insert it into Pending and repeat. The work item is deleted | 409 // insert it into Pending and repeat. The work item is deleted |
| 352 // after it is processed. | 410 // after it is processed. |
| 411 std::unique_ptr<VariableDeclarationList> GlobalInits( |
| 412 new VariableDeclarationList()); |
| 353 std::vector<EmitterWorkItem *> Pending; | 413 std::vector<EmitterWorkItem *> Pending; |
| 354 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); | 414 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); |
| 355 while (true) { | 415 while (true) { |
| 356 resizePending(Pending, DesiredSequenceNumber); | 416 resizePending(Pending, DesiredSequenceNumber); |
| 357 // See if Pending contains DesiredSequenceNumber. | 417 // See if Pending contains DesiredSequenceNumber. |
| 358 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; | 418 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; |
| 359 if (RawItem == nullptr) | 419 if (RawItem == nullptr) |
| 360 RawItem = emitQueueBlockingPop(); | 420 RawItem = emitQueueBlockingPop(); |
| 361 if (RawItem == nullptr) | 421 if (RawItem == nullptr) |
| 362 return; | 422 break; |
| 363 uint32_t ItemSeq = RawItem->getSequenceNumber(); | 423 uint32_t ItemSeq = RawItem->getSequenceNumber(); |
| 364 if (Threaded && ItemSeq != DesiredSequenceNumber) { | 424 if (Threaded && ItemSeq != DesiredSequenceNumber) { |
| 365 resizePending(Pending, ItemSeq); | 425 resizePending(Pending, ItemSeq); |
| 366 Pending[ItemSeq] = RawItem; | 426 Pending[ItemSeq] = RawItem; |
| 367 continue; | 427 continue; |
| 368 } | 428 } |
| 369 | 429 |
| 370 std::unique_ptr<EmitterWorkItem> Item(RawItem); | 430 std::unique_ptr<EmitterWorkItem> Item(RawItem); |
| 371 ++DesiredSequenceNumber; | 431 ++DesiredSequenceNumber; |
| 372 switch (Item->getKind()) { | 432 switch (Item->getKind()) { |
| 373 case EmitterWorkItem::WI_Nop: | 433 case EmitterWorkItem::WI_Nop: |
| 374 break; | 434 break; |
| 375 case EmitterWorkItem::WI_GlobalInits: { | 435 case EmitterWorkItem::WI_GlobalInits: { |
| 376 lowerGlobals(this, Item->getGlobalInits(), | 436 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); |
| 377 TargetDataLowering::createLowering(this).get()); | |
| 378 } break; | 437 } break; |
| 379 case EmitterWorkItem::WI_Asm: { | 438 case EmitterWorkItem::WI_Asm: { |
| 439 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); |
| 380 std::unique_ptr<Assembler> Asm = Item->getAsm(); | 440 std::unique_ptr<Assembler> Asm = Item->getAsm(); |
| 381 Asm->alignFunction(); | 441 Asm->alignFunction(); |
| 382 IceString MangledName = mangleName(Asm->getFunctionName()); | 442 IceString MangledName = mangleName(Asm->getFunctionName()); |
| 383 switch (getFlags().getOutFileType()) { | 443 switch (getFlags().getOutFileType()) { |
| 384 case FT_Elf: | 444 case FT_Elf: |
| 385 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), | 445 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), |
| 386 Asm.get()); | 446 Asm.get()); |
| 387 break; | 447 break; |
| 388 case FT_Iasm: { | 448 case FT_Iasm: { |
| 389 OstreamLocker L(this); | 449 OstreamLocker L(this); |
| 390 Cfg::emitTextHeader(MangledName, this, Asm.get()); | 450 Cfg::emitTextHeader(MangledName, this, Asm.get()); |
| 391 Asm->emitIASBytes(this); | 451 Asm->emitIASBytes(this); |
| 392 } break; | 452 } break; |
| 393 case FT_Asm: | 453 case FT_Asm: |
| 394 llvm::report_fatal_error("Unexpected FT_Asm"); | 454 llvm::report_fatal_error("Unexpected FT_Asm"); |
| 395 break; | 455 break; |
| 396 } | 456 } |
| 397 } break; | 457 } break; |
| 398 case EmitterWorkItem::WI_Cfg: { | 458 case EmitterWorkItem::WI_Cfg: { |
| 399 if (!ALLOW_DUMP) | 459 if (!ALLOW_DUMP) |
| 400 llvm::report_fatal_error("WI_Cfg work item created inappropriately"); | 460 llvm::report_fatal_error("WI_Cfg work item created inappropriately"); |
| 461 |
| 462 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); |
| 463 |
| 401 assert(getFlags().getOutFileType() == FT_Asm); | 464 assert(getFlags().getOutFileType() == FT_Asm); |
| 402 std::unique_ptr<Cfg> Func = Item->getCfg(); | 465 std::unique_ptr<Cfg> Func = Item->getCfg(); |
| 403 // Unfortunately, we have to temporarily install the Cfg in TLS | 466 // Unfortunately, we have to temporarily install the Cfg in TLS |
| 404 // because Variable::asType() uses the allocator to create the | 467 // because Variable::asType() uses the allocator to create the |
| 405 // differently-typed copy. | 468 // differently-typed copy. |
| 406 Cfg::setCurrentCfg(Func.get()); | 469 Cfg::setCurrentCfg(Func.get()); |
| 407 Func->emit(); | 470 Func->emit(); |
| 408 Cfg::setCurrentCfg(nullptr); | 471 Cfg::setCurrentCfg(nullptr); |
| 409 dumpStats(Func->getFunctionName()); | 472 dumpStats(Func->getFunctionName()); |
| 410 } break; | 473 } break; |
| 411 } | 474 } |
| 412 } | 475 } |
| 476 |
| 477 lowerGlobals(this, std::move(GlobalInits), |
| 478 TargetDataLowering::createLowering(this).get()); |
| 413 } | 479 } |
| 414 | 480 |
| 415 // Scan a string for S[0-9A-Z]*_ patterns and replace them with | 481 // Scan a string for S[0-9A-Z]*_ patterns and replace them with |
| 416 // S<num>_ where <num> is the next base-36 value. If a type name | 482 // S<num>_ where <num> is the next base-36 value. If a type name |
| 417 // legitimately contains that pattern, then the substitution will be | 483 // legitimately contains that pattern, then the substitution will be |
| 418 // made in error and most likely the link will fail. In this case, | 484 // made in error and most likely the link will fail. In this case, |
| 419 // the test classes can be rewritten not to use that pattern, which is | 485 // the test classes can be rewritten not to use that pattern, which is |
| 420 // much simpler and more reliable than implementing a full demangling | 486 // much simpler and more reliable than implementing a full demangling |
| 421 // parser. Another substitution-in-error may occur if a type | 487 // parser. Another substitution-in-error may occur if a type |
| 422 // identifier ends with the pattern S[0-9A-Z]*, because an immediately | 488 // identifier ends with the pattern S[0-9A-Z]*, because an immediately |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 Ctx = Func->getContext(); | 895 Ctx = Func->getContext(); |
| 830 Active = | 896 Active = |
| 831 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); | 897 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
| 832 if (Active) | 898 if (Active) |
| 833 Ctx->pushTimer(ID, StackID); | 899 Ctx->pushTimer(ID, StackID); |
| 834 } | 900 } |
| 835 | 901 |
| 836 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); | 902 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
| 837 | 903 |
| 838 } // end of namespace Ice | 904 } // end of namespace Ice |
| OLD | NEW |