145 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- BasicBlockSectionsProfileReader.cpp -------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // Implementation of the basic block sections profile reader pass. It parses
 | |
| // and stores the basic block sections profile file (which is specified via the
 | |
| // `-basic-block-sections` flag).
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
 | |
| #include "llvm/ADT/SmallSet.h"
 | |
| #include "llvm/ADT/SmallVector.h"
 | |
| #include "llvm/ADT/StringMap.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| #include "llvm/Support/Error.h"
 | |
| #include "llvm/Support/LineIterator.h"
 | |
| #include "llvm/Support/MemoryBuffer.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| char BasicBlockSectionsProfileReader::ID = 0;
 | |
| INITIALIZE_PASS(BasicBlockSectionsProfileReader, "bbsections-profile-reader",
 | |
|                 "Reads and parses a basic block sections profile.", false,
 | |
|                 false)
 | |
| 
 | |
| bool BasicBlockSectionsProfileReader::isFunctionHot(StringRef FuncName) const {
 | |
|   return getBBClusterInfoForFunction(FuncName).first;
 | |
| }
 | |
| 
 | |
| std::pair<bool, SmallVector<BBClusterInfo>>
 | |
| BasicBlockSectionsProfileReader::getBBClusterInfoForFunction(
 | |
|     StringRef FuncName) const {
 | |
|   std::pair<bool, SmallVector<BBClusterInfo>> cluster_info(false, {});
 | |
|   auto R = ProgramBBClusterInfo.find(getAliasName(FuncName));
 | |
|   if (R != ProgramBBClusterInfo.end()) {
 | |
|     cluster_info.second = R->second;
 | |
|     cluster_info.first = true;
 | |
|   }
 | |
|   return cluster_info;
 | |
| }
 | |
| 
 | |
| // Basic Block Sections can be enabled for a subset of machine basic blocks.
 | |
| // This is done by passing a file containing names of functions for which basic
 | |
| // block sections are desired.  Additionally, machine basic block ids of the
 | |
| // functions can also be specified for a finer granularity. Moreover, a cluster
 | |
| // of basic blocks could be assigned to the same section.
 | |
| // A file with basic block sections for all of function main and three blocks
 | |
| // for function foo (of which 1 and 2 are placed in a cluster) looks like this:
 | |
| // ----------------------------
 | |
| // list.txt:
 | |
| // !main
 | |
| // !foo
 | |
| // !!1 2
 | |
| // !!4
 | |
| static Error getBBClusterInfo(const MemoryBuffer *MBuf,
 | |
|                               ProgramBBClusterInfoMapTy &ProgramBBClusterInfo,
 | |
|                               StringMap<StringRef> &FuncAliasMap) {
 | |
|   assert(MBuf);
 | |
|   line_iterator LineIt(*MBuf, /*SkipBlanks=*/true, /*CommentMarker=*/'#');
 | |
| 
 | |
|   auto invalidProfileError = [&](auto Message) {
 | |
|     return make_error<StringError>(
 | |
|         Twine("Invalid profile " + MBuf->getBufferIdentifier() + " at line " +
 | |
|               Twine(LineIt.line_number()) + ": " + Message),
 | |
|         inconvertibleErrorCode());
 | |
|   };
 | |
| 
 | |
|   auto FI = ProgramBBClusterInfo.end();
 | |
| 
 | |
|   // Current cluster ID corresponding to this function.
 | |
|   unsigned CurrentCluster = 0;
 | |
|   // Current position in the current cluster.
 | |
|   unsigned CurrentPosition = 0;
 | |
| 
 | |
|   // Temporary set to ensure every basic block ID appears once in the clusters
 | |
|   // of a function.
 | |
|   SmallSet<unsigned, 4> FuncBBIDs;
 | |
| 
 | |
|   for (; !LineIt.is_at_eof(); ++LineIt) {
 | |
|     StringRef S(*LineIt);
 | |
|     if (S[0] == '@')
 | |
|       continue;
 | |
|     // Check for the leading "!"
 | |
|     if (!S.consume_front("!") || S.empty())
 | |
|       break;
 | |
|     // Check for second "!" which indicates a cluster of basic blocks.
 | |
|     if (S.consume_front("!")) {
 | |
|       if (FI == ProgramBBClusterInfo.end())
 | |
|         return invalidProfileError(
 | |
|             "Cluster list does not follow a function name specifier.");
 | |
|       SmallVector<StringRef, 4> BBIndexes;
 | |
|       S.split(BBIndexes, ' ');
 | |
|       // Reset current cluster position.
 | |
|       CurrentPosition = 0;
 | |
|       for (auto BBIndexStr : BBIndexes) {
 | |
|         unsigned long long BBIndex;
 | |
|         if (getAsUnsignedInteger(BBIndexStr, 10, BBIndex))
 | |
|           return invalidProfileError(Twine("Unsigned integer expected: '") +
 | |
|                                      BBIndexStr + "'.");
 | |
|         if (!FuncBBIDs.insert(BBIndex).second)
 | |
|           return invalidProfileError(Twine("Duplicate basic block id found '") +
 | |
|                                      BBIndexStr + "'.");
 | |
|         if (!BBIndex && CurrentPosition)
 | |
|           return invalidProfileError("Entry BB (0) does not begin a cluster.");
 | |
| 
 | |
|         FI->second.emplace_back(BBClusterInfo{
 | |
|             ((unsigned)BBIndex), CurrentCluster, CurrentPosition++});
 | |
|       }
 | |
|       CurrentCluster++;
 | |
|     } else { // This is a function name specifier.
 | |
|       // Function aliases are separated using '/'. We use the first function
 | |
|       // name for the cluster info mapping and delegate all other aliases to
 | |
|       // this one.
 | |
|       SmallVector<StringRef, 4> Aliases;
 | |
|       S.split(Aliases, '/');
 | |
|       for (size_t i = 1; i < Aliases.size(); ++i)
 | |
|         FuncAliasMap.try_emplace(Aliases[i], Aliases.front());
 | |
| 
 | |
|       // Prepare for parsing clusters of this function name.
 | |
|       // Start a new cluster map for this function name.
 | |
|       FI = ProgramBBClusterInfo.try_emplace(Aliases.front()).first;
 | |
|       CurrentCluster = 0;
 | |
|       FuncBBIDs.clear();
 | |
|     }
 | |
|   }
 | |
|   return Error::success();
 | |
| }
 | |
| 
 | |
| void BasicBlockSectionsProfileReader::initializePass() {
 | |
|   if (!MBuf)
 | |
|     return;
 | |
|   if (auto Err = getBBClusterInfo(MBuf, ProgramBBClusterInfo, FuncAliasMap))
 | |
|     report_fatal_error(std::move(Err));
 | |
| }
 | |
| 
 | |
| ImmutablePass *
 | |
| llvm::createBasicBlockSectionsProfileReaderPass(const MemoryBuffer *Buf) {
 | |
|   return new BasicBlockSectionsProfileReader(Buf);
 | |
| }
 |