Chromium Code Reviews| 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 VariableDeclaration *blockProfileInfo(const VariableDeclarationList &Globals) { | |
| 327 auto *Var = VariableDeclaration::create(); | |
| 328 Var->setAlignment(8); | |
| 329 Var->setIsConstant(true); | |
| 330 Var->setName("__Sz_block_profile_info"); | |
| 331 Var->setLinkage(llvm::GlobalValue::ExternalLinkage); | |
| 332 for (const auto *Global : Globals) { | |
| 333 if (Cfg::isProfileGlobal(*Global)) { | |
| 334 constexpr RelocOffsetT BlockExecutionCounterOffset = 0; | |
| 335 Var->addInitializer(new VariableDeclaration::RelocInitializer( | |
| 336 Global, BlockExecutionCounterOffset)); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 constexpr SizeT ByteCountOf64BitNullPtr = 8; | |
|
Jim Stichnoth
2015/06/09 16:39:46
I think the 8 could be typeWidthInBytes(IceType_i6
John
2015/06/09 22:01:16
Done.
| |
| 341 Var->addInitializer( | |
| 342 new VariableDeclaration::ZeroInitializer(ByteCountOf64BitNullPtr)); | |
| 343 | |
| 344 return Var; | |
| 345 } | |
| 346 | |
| 347 void addBlockProfileInfoArrayToGlobals(VariableDeclarationList *Globals) { | |
| 348 // Purposefully create the Var temp to prevent bugs in case the compiler | |
| 349 // reorders instructions in a way that Globals is extended before the call | |
| 350 // to profileInfoArray. | |
| 351 auto *Var = blockProfileInfo(*Globals); | |
| 352 Globals->push_back(Var); | |
| 353 } | |
| 354 | |
| 319 void lowerGlobals(GlobalContext *Ctx, | 355 void lowerGlobals(GlobalContext *Ctx, |
| 320 std::unique_ptr<VariableDeclarationList> VariableDeclarations, | 356 std::unique_ptr<VariableDeclarationList> VariableDeclarations, |
| 321 TargetDataLowering *DataLowering) { | 357 TargetDataLowering *DataLowering) { |
| 322 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); | 358 TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx); |
| 323 const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() && | 359 const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() && |
| 324 Ctx->getFlags().getVerboseFocusOn().empty(); | 360 Ctx->getFlags().getVerboseFocusOn().empty(); |
| 325 if (DumpGlobalVariables) { | 361 if (DumpGlobalVariables) { |
| 326 OstreamLocker L(Ctx); | 362 OstreamLocker L(Ctx); |
| 327 Ostream &Stream = Ctx->getStrDump(); | 363 Ostream &Stream = Ctx->getStrDump(); |
| 328 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { | 364 for (const Ice::VariableDeclaration *Global : *VariableDeclarations) { |
| 329 Global->dump(Ctx, Stream); | 365 Global->dump(Ctx, Stream); |
| 330 } | 366 } |
| 331 } | 367 } |
| 332 if (Ctx->getFlags().getDisableTranslation()) | 368 if (Ctx->getFlags().getDisableTranslation()) |
| 333 return; | 369 return; |
| 370 | |
| 371 // There should be no need to emit the block_profile_info array if profiling | |
| 372 // is disabled. In practice, given that szrt_profiler.o will always be | |
| 373 // embedded in the application, we need to add it. In a non-profiled build | |
| 374 // this array will only contain the nullptr terminator. | |
| 375 addBlockProfileInfoArrayToGlobals(VariableDeclarations.get()); | |
| 376 | |
| 334 DataLowering->lowerGlobals(std::move(VariableDeclarations)); | 377 DataLowering->lowerGlobals(std::move(VariableDeclarations)); |
| 335 } | 378 } |
| 336 | 379 |
| 337 // Ensure Pending is large enough that Pending[Index] is valid. | 380 // Ensure Pending is large enough that Pending[Index] is valid. |
| 338 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { | 381 void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { |
| 339 if (Index >= Pending.size()) | 382 if (Index >= Pending.size()) |
| 340 Pending.resize(Index + 1); | 383 Pending.resize(Index + 1); |
| 341 } | 384 } |
| 342 | 385 |
| 386 void addAllIfNotNull(std::unique_ptr<VariableDeclarationList> src, | |
| 387 VariableDeclarationList *dst) { | |
| 388 if (src != nullptr) { | |
| 389 dst->insert(dst->end(), src->begin(), src->end()); | |
| 390 } | |
| 391 } | |
| 392 | |
| 343 } // end of anonymous namespace | 393 } // end of anonymous namespace |
| 344 | 394 |
| 345 void GlobalContext::emitItems() { | 395 void GlobalContext::emitItems() { |
| 346 const bool Threaded = !getFlags().isSequential(); | 396 const bool Threaded = !getFlags().isSequential(); |
| 347 // Pending is a vector containing the reassembled, ordered list of | 397 // Pending is a vector containing the reassembled, ordered list of |
| 348 // work items. When we're ready for the next item, we first check | 398 // 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 | 399 // 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 | 400 // 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 | 401 // insert it into Pending and repeat. The work item is deleted |
| 352 // after it is processed. | 402 // after it is processed. |
| 403 std::unique_ptr<VariableDeclarationList> GlobalInits( | |
| 404 new VariableDeclarationList()); | |
| 353 std::vector<EmitterWorkItem *> Pending; | 405 std::vector<EmitterWorkItem *> Pending; |
| 354 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); | 406 uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); |
| 355 while (true) { | 407 while (true) { |
| 356 resizePending(Pending, DesiredSequenceNumber); | 408 resizePending(Pending, DesiredSequenceNumber); |
| 357 // See if Pending contains DesiredSequenceNumber. | 409 // See if Pending contains DesiredSequenceNumber. |
| 358 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; | 410 EmitterWorkItem *RawItem = Pending[DesiredSequenceNumber]; |
| 359 if (RawItem == nullptr) | 411 if (RawItem == nullptr) |
| 360 RawItem = emitQueueBlockingPop(); | 412 RawItem = emitQueueBlockingPop(); |
| 361 if (RawItem == nullptr) | 413 if (RawItem == nullptr) |
| 362 return; | 414 break; |
| 363 uint32_t ItemSeq = RawItem->getSequenceNumber(); | 415 uint32_t ItemSeq = RawItem->getSequenceNumber(); |
| 364 if (Threaded && ItemSeq != DesiredSequenceNumber) { | 416 if (Threaded && ItemSeq != DesiredSequenceNumber) { |
| 365 resizePending(Pending, ItemSeq); | 417 resizePending(Pending, ItemSeq); |
| 366 Pending[ItemSeq] = RawItem; | 418 Pending[ItemSeq] = RawItem; |
| 367 continue; | 419 continue; |
| 368 } | 420 } |
| 369 | 421 |
| 370 std::unique_ptr<EmitterWorkItem> Item(RawItem); | 422 std::unique_ptr<EmitterWorkItem> Item(RawItem); |
| 371 ++DesiredSequenceNumber; | 423 ++DesiredSequenceNumber; |
| 372 switch (Item->getKind()) { | 424 switch (Item->getKind()) { |
| 373 case EmitterWorkItem::WI_Nop: | 425 case EmitterWorkItem::WI_Nop: |
| 374 break; | 426 break; |
| 375 case EmitterWorkItem::WI_GlobalInits: { | 427 case EmitterWorkItem::WI_GlobalInits: { |
| 376 lowerGlobals(this, Item->getGlobalInits(), | 428 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); |
| 377 TargetDataLowering::createLowering(this).get()); | |
| 378 } break; | 429 } break; |
| 379 case EmitterWorkItem::WI_Asm: { | 430 case EmitterWorkItem::WI_Asm: { |
| 431 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); | |
| 380 std::unique_ptr<Assembler> Asm = Item->getAsm(); | 432 std::unique_ptr<Assembler> Asm = Item->getAsm(); |
| 381 Asm->alignFunction(); | 433 Asm->alignFunction(); |
| 382 IceString MangledName = mangleName(Asm->getFunctionName()); | 434 IceString MangledName = mangleName(Asm->getFunctionName()); |
| 383 switch (getFlags().getOutFileType()) { | 435 switch (getFlags().getOutFileType()) { |
| 384 case FT_Elf: | 436 case FT_Elf: |
| 385 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), | 437 getObjectWriter()->writeFunctionCode(MangledName, Asm->getInternal(), |
| 386 Asm.get()); | 438 Asm.get()); |
| 387 break; | 439 break; |
| 388 case FT_Iasm: { | 440 case FT_Iasm: { |
| 389 OstreamLocker L(this); | 441 OstreamLocker L(this); |
| 390 Cfg::emitTextHeader(MangledName, this, Asm.get()); | 442 Cfg::emitTextHeader(MangledName, this, Asm.get()); |
| 391 Asm->emitIASBytes(this); | 443 Asm->emitIASBytes(this); |
| 392 } break; | 444 } break; |
| 393 case FT_Asm: | 445 case FT_Asm: |
| 394 llvm::report_fatal_error("Unexpected FT_Asm"); | 446 llvm::report_fatal_error("Unexpected FT_Asm"); |
| 395 break; | 447 break; |
| 396 } | 448 } |
| 397 } break; | 449 } break; |
| 398 case EmitterWorkItem::WI_Cfg: { | 450 case EmitterWorkItem::WI_Cfg: { |
| 399 if (!ALLOW_DUMP) | 451 if (!ALLOW_DUMP) |
| 400 llvm::report_fatal_error("WI_Cfg work item created inappropriately"); | 452 llvm::report_fatal_error("WI_Cfg work item created inappropriately"); |
| 453 | |
| 454 addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); | |
| 455 | |
| 401 assert(getFlags().getOutFileType() == FT_Asm); | 456 assert(getFlags().getOutFileType() == FT_Asm); |
| 402 std::unique_ptr<Cfg> Func = Item->getCfg(); | 457 std::unique_ptr<Cfg> Func = Item->getCfg(); |
| 403 // Unfortunately, we have to temporarily install the Cfg in TLS | 458 // Unfortunately, we have to temporarily install the Cfg in TLS |
| 404 // because Variable::asType() uses the allocator to create the | 459 // because Variable::asType() uses the allocator to create the |
| 405 // differently-typed copy. | 460 // differently-typed copy. |
| 406 Cfg::setCurrentCfg(Func.get()); | 461 Cfg::setCurrentCfg(Func.get()); |
| 407 Func->emit(); | 462 Func->emit(); |
| 408 Cfg::setCurrentCfg(nullptr); | 463 Cfg::setCurrentCfg(nullptr); |
| 409 dumpStats(Func->getFunctionName()); | 464 dumpStats(Func->getFunctionName()); |
| 410 } break; | 465 } break; |
| 411 } | 466 } |
| 412 } | 467 } |
| 468 | |
| 469 lowerGlobals(this, std::move(GlobalInits), | |
| 470 TargetDataLowering::createLowering(this).get()); | |
| 413 } | 471 } |
| 414 | 472 |
| 415 // Scan a string for S[0-9A-Z]*_ patterns and replace them with | 473 // 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 | 474 // S<num>_ where <num> is the next base-36 value. If a type name |
| 417 // legitimately contains that pattern, then the substitution will be | 475 // legitimately contains that pattern, then the substitution will be |
| 418 // made in error and most likely the link will fail. In this case, | 476 // 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 | 477 // the test classes can be rewritten not to use that pattern, which is |
| 420 // much simpler and more reliable than implementing a full demangling | 478 // much simpler and more reliable than implementing a full demangling |
| 421 // parser. Another substitution-in-error may occur if a type | 479 // parser. Another substitution-in-error may occur if a type |
| 422 // identifier ends with the pattern S[0-9A-Z]*, because an immediately | 480 // 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(); | 887 Ctx = Func->getContext(); |
| 830 Active = | 888 Active = |
| 831 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); | 889 Func->getFocusedTiming() || Ctx->getFlags().getSubzeroTimingEnabled(); |
| 832 if (Active) | 890 if (Active) |
| 833 Ctx->pushTimer(ID, StackID); | 891 Ctx->pushTimer(ID, StackID); |
| 834 } | 892 } |
| 835 | 893 |
| 836 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); | 894 ICE_TLS_DEFINE_FIELD(GlobalContext::ThreadContext *, GlobalContext, TLS); |
| 837 | 895 |
| 838 } // end of namespace Ice | 896 } // end of namespace Ice |
| OLD | NEW |