112 lines · cpp
1//===--------------------- Support.cpp --------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file implements a few helper functions used by various pipeline11/// components.12///13//===----------------------------------------------------------------------===//14 15#include "llvm/MCA/Support.h"16#include "llvm/MC/MCSchedule.h"17#include <numeric>18 19namespace llvm {20namespace mca {21 22#define DEBUG_TYPE "llvm-mca"23 24ReleaseAtCycles &ReleaseAtCycles::operator+=(const ReleaseAtCycles &RHS) {25 if (Denominator == RHS.Denominator)26 Numerator += RHS.Numerator;27 else {28 // Create a common denominator for LHS and RHS by calculating the least29 // common multiple from the GCD.30 unsigned GCD = std::gcd(Denominator, RHS.Denominator);31 unsigned LCM = (Denominator * RHS.Denominator) / GCD;32 unsigned LHSNumerator = Numerator * (LCM / Denominator);33 unsigned RHSNumerator = RHS.Numerator * (LCM / RHS.Denominator);34 Numerator = LHSNumerator + RHSNumerator;35 Denominator = LCM;36 }37 return *this;38}39 40void computeProcResourceMasks(const MCSchedModel &SM,41 MutableArrayRef<uint64_t> Masks) {42 unsigned ProcResourceID = 0;43 44 assert(Masks.size() == SM.getNumProcResourceKinds() &&45 "Invalid number of elements");46 // Resource at index 0 is the 'InvalidUnit'. Set an invalid mask for it.47 Masks[0] = 0;48 49 // Create a unique bitmask for every processor resource unit.50 for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {51 const MCProcResourceDesc &Desc = *SM.getProcResource(I);52 if (Desc.SubUnitsIdxBegin)53 continue;54 Masks[I] = 1ULL << ProcResourceID;55 ProcResourceID++;56 }57 58 // Create a unique bitmask for every processor resource group.59 for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {60 const MCProcResourceDesc &Desc = *SM.getProcResource(I);61 if (!Desc.SubUnitsIdxBegin)62 continue;63 Masks[I] = 1ULL << ProcResourceID;64 for (unsigned U = 0; U < Desc.NumUnits; ++U) {65 uint64_t OtherMask = Masks[Desc.SubUnitsIdxBegin[U]];66 Masks[I] |= OtherMask;67 }68 ProcResourceID++;69 }70 71#ifndef NDEBUG72 LLVM_DEBUG(dbgs() << "\nProcessor resource masks:"73 << "\n");74 for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {75 const MCProcResourceDesc &Desc = *SM.getProcResource(I);76 LLVM_DEBUG(dbgs() << '[' << format_decimal(I,2) << "] " << " - "77 << format_hex(Masks[I],16) << " - "78 << Desc.Name << '\n');79 }80#endif81}82 83double computeBlockRThroughput(const MCSchedModel &SM, unsigned DispatchWidth,84 unsigned NumMicroOps,85 ArrayRef<unsigned> ProcResourceUsage) {86 // The block throughput is bounded from above by the hardware dispatch87 // throughput. That is because the DispatchWidth is an upper bound on the88 // number of opcodes that can be part of a single dispatch group.89 double Max = static_cast<double>(NumMicroOps) / DispatchWidth;90 91 // The block throughput is also limited by the amount of hardware parallelism.92 // The number of available resource units affects the resource pressure93 // distribution, as well as how many blocks can be executed every cycle.94 for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {95 unsigned ReleaseAtCycles = ProcResourceUsage[I];96 if (!ReleaseAtCycles)97 continue;98 99 const MCProcResourceDesc &MCDesc = *SM.getProcResource(I);100 double Throughput = static_cast<double>(ReleaseAtCycles) / MCDesc.NumUnits;101 Max = std::max(Max, Throughput);102 }103 104 // The block reciprocal throughput is computed as the MAX of:105 // - (NumMicroOps / DispatchWidth)106 // - (NumUnits / ReleaseAtCycles) for every consumed processor resource.107 return Max;108}109 110} // namespace mca111} // namespace llvm112