2020-08-05 17:11:48 -07:00
|
|
|
//===-- BasicBlockSections.cpp ---=========--------------------------------===//
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2020-08-05 17:11:48 -07:00
|
|
|
// BasicBlockSections implementation.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
|
|
|
// The purpose of this pass is to assign sections to basic blocks when
|
2020-06-01 23:17:29 -07:00
|
|
|
// -fbasic-block-sections= option is used. Further, with profile information
|
|
|
|
// only the subset of basic blocks with profiles are placed in separate sections
|
|
|
|
// and the rest are grouped in a cold section. The exception handling blocks are
|
2020-04-13 12:14:42 -07:00
|
|
|
// treated specially to ensure they are all in one seciton.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
|
|
|
// Basic Block Sections
|
|
|
|
// ====================
|
|
|
|
//
|
2020-06-01 23:17:29 -07:00
|
|
|
// With option, -fbasic-block-sections=list, every function may be split into
|
2020-04-13 12:14:42 -07:00
|
|
|
// clusters of basic blocks. Every cluster will be emitted into a separate
|
|
|
|
// section with its basic blocks sequenced in the given order. To get the
|
|
|
|
// optimized performance, the clusters must form an optimal BB layout for the
|
2021-07-29 19:20:12 -07:00
|
|
|
// function. We insert a symbol at the beginning of every cluster's section to
|
|
|
|
// allow the linker to reorder the sections in any arbitrary sequence. A global
|
|
|
|
// order of these sections would encapsulate the function layout.
|
|
|
|
// For example, consider the following clusters for a function foo (consisting
|
|
|
|
// of 6 basic blocks 0, 1, ..., 5).
|
|
|
|
//
|
|
|
|
// 0 2
|
|
|
|
// 1 3 5
|
|
|
|
//
|
|
|
|
// * Basic blocks 0 and 2 are placed in one section with symbol `foo`
|
|
|
|
// referencing the beginning of this section.
|
|
|
|
// * Basic blocks 1, 3, 5 are placed in a separate section. A new symbol
|
|
|
|
// `foo.__part.1` will reference the beginning of this section.
|
|
|
|
// * Basic block 4 (note that it is not referenced in the list) is placed in
|
|
|
|
// one section, and a new symbol `foo.cold` will point to it.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
2020-04-13 12:14:42 -07:00
|
|
|
// There are a couple of challenges to be addressed:
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
2020-04-13 12:14:42 -07:00
|
|
|
// 1. The last basic block of every cluster should not have any implicit
|
|
|
|
// fallthrough to its next basic block, as it can be reordered by the linker.
|
|
|
|
// The compiler should make these fallthroughs explicit by adding
|
|
|
|
// unconditional jumps..
|
|
|
|
//
|
|
|
|
// 2. All inter-cluster branch targets would now need to be resolved by the
|
2020-03-16 15:56:02 -07:00
|
|
|
// linker as they cannot be calculated during compile time. This is done
|
|
|
|
// using static relocations. Further, the compiler tries to use short branch
|
|
|
|
// instructions on some ISAs for small branch offsets. This is not possible
|
2020-04-13 12:14:42 -07:00
|
|
|
// for inter-cluster branches as the offset is not determined at compile
|
|
|
|
// time, and therefore, long branch instructions have to be used for those.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
2020-04-13 12:14:42 -07:00
|
|
|
// 3. Debug Information (DebugInfo) and Call Frame Information (CFI) emission
|
2020-03-16 15:56:02 -07:00
|
|
|
// needs special handling with basic block sections. DebugInfo needs to be
|
|
|
|
// emitted with more relocations as basic block sections can break a
|
|
|
|
// function into potentially several disjoint pieces, and CFI needs to be
|
2020-04-13 12:14:42 -07:00
|
|
|
// emitted per cluster. This also bloats the object file and binary sizes.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
|
|
|
// Basic Block Labels
|
|
|
|
// ==================
|
|
|
|
//
|
2022-06-28 07:41:40 -07:00
|
|
|
// With -fbasic-block-sections=labels, we encode the offsets of BB addresses of
|
2020-10-08 11:12:40 -07:00
|
|
|
// every function into the .llvm_bb_addr_map section. Along with the function
|
|
|
|
// symbols, this allows for mapping of virtual addresses in PMU profiles back to
|
|
|
|
// the corresponding basic blocks. This logic is implemented in AsmPrinter. This
|
2020-09-14 10:16:44 -07:00
|
|
|
// pass only assigns the BBSectionType of every function to ``labels``.
|
2020-03-16 15:56:02 -07:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2020-03-16 15:56:02 -07:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2022-12-13 09:52:05 -08:00
|
|
|
#include "llvm/CodeGen/BasicBlockSectionUtils.h"
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
#include "llvm/CodeGen/BasicBlockSectionsProfileReader.h"
|
2020-03-16 15:56:02 -07:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
|
|
#include "llvm/CodeGen/Passes.h"
|
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
|
|
#include "llvm/InitializePasses.h"
|
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2022-11-26 14:24:38 -08:00
|
|
|
#include <optional>
|
2020-03-16 15:56:02 -07:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2020-09-16 21:40:00 -07:00
|
|
|
// Placing the cold clusters in a separate section mitigates against poor
|
|
|
|
// profiles and allows optimizations such as hugepage mapping to be applied at a
|
2020-10-07 11:42:02 -07:00
|
|
|
// section granularity. Defaults to ".text.split." which is recognized by lld
|
|
|
|
// via the `-z keep-text-section-prefix` flag.
|
2020-09-16 21:40:00 -07:00
|
|
|
cl::opt<std::string> llvm::BBSectionsColdTextPrefix(
|
|
|
|
"bbsections-cold-text-prefix",
|
|
|
|
cl::desc("The text prefix to use for cold basic block clusters"),
|
2020-10-07 11:42:02 -07:00
|
|
|
cl::init(".text.split."), cl::Hidden);
|
2020-09-16 21:40:00 -07:00
|
|
|
|
2021-01-29 18:47:26 -08:00
|
|
|
cl::opt<bool> BBSectionsDetectSourceDrift(
|
|
|
|
"bbsections-detect-source-drift",
|
|
|
|
cl::desc("This checks if there is a fdo instr. profile hash "
|
|
|
|
"mismatch for this function"),
|
|
|
|
cl::init(true), cl::Hidden);
|
|
|
|
|
2020-03-16 15:56:02 -07:00
|
|
|
namespace {
|
|
|
|
|
2020-08-05 17:11:48 -07:00
|
|
|
class BasicBlockSections : public MachineFunctionPass {
|
2020-03-16 15:56:02 -07:00
|
|
|
public:
|
|
|
|
static char ID;
|
2020-04-13 12:14:42 -07:00
|
|
|
|
2022-05-26 19:27:05 -07:00
|
|
|
BasicBlockSectionsProfileReader *BBSectionsProfileReader = nullptr;
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-08-05 17:11:48 -07:00
|
|
|
BasicBlockSections() : MachineFunctionPass(ID) {
|
|
|
|
initializeBasicBlockSectionsPass(*PassRegistry::getPassRegistry());
|
2020-04-13 12:14:42 -07:00
|
|
|
}
|
|
|
|
|
2020-03-16 15:56:02 -07:00
|
|
|
StringRef getPassName() const override {
|
|
|
|
return "Basic Block Sections Analysis";
|
|
|
|
}
|
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
|
|
|
|
|
|
|
/// Identify basic blocks that need separate sections and prepare to emit them
|
|
|
|
/// accordingly.
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2020-08-05 17:11:48 -07:00
|
|
|
char BasicBlockSections::ID = 0;
|
|
|
|
INITIALIZE_PASS(BasicBlockSections, "bbsections-prepare",
|
2020-04-13 12:14:42 -07:00
|
|
|
"Prepares for basic block sections, by splitting functions "
|
|
|
|
"into clusters of basic blocks.",
|
|
|
|
false, false)
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// This function updates and optimizes the branching instructions of every basic
|
|
|
|
// block in a given function to account for changes in the layout.
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
static void
|
|
|
|
updateBranches(MachineFunction &MF,
|
|
|
|
const SmallVector<MachineBasicBlock *> &PreLayoutFallThroughs) {
|
2020-04-13 12:14:42 -07:00
|
|
|
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
|
|
|
SmallVector<MachineOperand, 4> Cond;
|
|
|
|
for (auto &MBB : MF) {
|
|
|
|
auto NextMBBI = std::next(MBB.getIterator());
|
|
|
|
auto *FTMBB = PreLayoutFallThroughs[MBB.getNumber()];
|
|
|
|
// If this block had a fallthrough before we need an explicit unconditional
|
|
|
|
// branch to that block if either
|
|
|
|
// 1- the block ends a section, which means its next block may be
|
|
|
|
// reorderd by the linker, or
|
|
|
|
// 2- the fallthrough block is not adjacent to the block in the new
|
|
|
|
// order.
|
|
|
|
if (FTMBB && (MBB.isEndSection() || &*NextMBBI != FTMBB))
|
|
|
|
TII->insertUnconditionalBranch(MBB, FTMBB, MBB.findBranchDebugLoc());
|
|
|
|
|
|
|
|
// We do not optimize branches for machine basic blocks ending sections, as
|
|
|
|
// their adjacent block might be reordered by the linker.
|
|
|
|
if (MBB.isEndSection())
|
|
|
|
continue;
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// It might be possible to optimize branches by flipping the branch
|
|
|
|
// condition.
|
|
|
|
Cond.clear();
|
|
|
|
MachineBasicBlock *TBB = nullptr, *FBB = nullptr; // For analyzeBranch.
|
|
|
|
if (TII->analyzeBranch(MBB, TBB, FBB, Cond))
|
|
|
|
continue;
|
MachineBasicBlock::updateTerminator now requires an explicit layout successor.
Previously, it tried to infer the correct destination block from the
successor list, but this is a rather tricky propspect, given the
existence of successors that occur mid-block, such as invoke, and
potentially in the future, callbr/INLINEASM_BR. (INLINEASM_BR, in
particular would be problematic, because its successor blocks are not
distinct from "normal" successors, as EHPads are.)
Instead, require the caller to pass in the expected fallthrough
successor explicitly. In most callers, the correct block is
immediately clear. But, in MachineBlockPlacement, we do need to record
the original ordering, before starting to reorder blocks.
Unfortunately, the goal of decoupling the behavior of end-of-block
jumps from the successor list has not been fully accomplished in this
patch, as there is currently no other way to determine whether a block
is intended to fall-through, or end as unreachable. Further work is
needed there.
Differential Revision: https://reviews.llvm.org/D79605
2020-02-19 10:41:28 -05:00
|
|
|
MBB.updateTerminator(FTMBB);
|
2020-04-13 12:14:42 -07:00
|
|
|
}
|
|
|
|
}
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// This function provides the BBCluster information associated with a function.
|
|
|
|
// Returns true if a valid association exists and false otherwise.
|
2022-05-26 19:27:05 -07:00
|
|
|
bool getBBClusterInfoForFunction(
|
|
|
|
const MachineFunction &MF,
|
|
|
|
BasicBlockSectionsProfileReader *BBSectionsProfileReader,
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
DenseMap<unsigned, BBClusterInfo> &V) {
|
2020-04-13 12:14:42 -07:00
|
|
|
|
|
|
|
// Find the assoicated cluster information.
|
2022-05-26 19:27:05 -07:00
|
|
|
std::pair<bool, SmallVector<BBClusterInfo, 4>> P =
|
|
|
|
BBSectionsProfileReader->getBBClusterInfoForFunction(MF.getName());
|
|
|
|
if (!P.first)
|
2020-04-13 12:14:42 -07:00
|
|
|
return false;
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2022-05-26 19:27:05 -07:00
|
|
|
if (P.second.empty()) {
|
2020-04-13 12:14:42 -07:00
|
|
|
// This indicates that sections are desired for all basic blocks of this
|
|
|
|
// function. We clear the BBClusterInfo vector to denote this.
|
|
|
|
V.clear();
|
|
|
|
return true;
|
2020-04-13 11:39:23 -07:00
|
|
|
}
|
2020-04-13 12:12:34 -07:00
|
|
|
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
for (const BBClusterInfo &BBCI : P.second)
|
|
|
|
V[BBCI.BBID] = BBCI;
|
2020-04-13 12:14:42 -07:00
|
|
|
return true;
|
2020-03-16 15:56:02 -07:00
|
|
|
}
|
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// This function sorts basic blocks according to the cluster's information.
|
|
|
|
// All explicitly specified clusters of basic blocks will be ordered
|
|
|
|
// accordingly. All non-specified BBs go into a separate "Cold" section.
|
|
|
|
// Additionally, if exception handling landing pads end up in more than one
|
|
|
|
// clusters, they are moved into a single "Exception" section. Eventually,
|
|
|
|
// clusters are ordered in increasing order of their IDs, with the "Exception"
|
|
|
|
// and "Cold" succeeding all other clusters.
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
// FuncBBClusterInfo represent the cluster information for basic blocks. It
|
|
|
|
// maps from BBID of basic blocks to their cluster information. If this is
|
|
|
|
// empty, it means unique sections for all basic blocks in the function.
|
|
|
|
static void
|
|
|
|
assignSections(MachineFunction &MF,
|
|
|
|
const DenseMap<unsigned, BBClusterInfo> &FuncBBClusterInfo) {
|
2020-04-13 12:14:42 -07:00
|
|
|
assert(MF.hasBBSections() && "BB Sections is not set for function.");
|
|
|
|
// This variable stores the section ID of the cluster containing eh_pads (if
|
|
|
|
// all eh_pads are one cluster). If more than one cluster contain eh_pads, we
|
|
|
|
// set it equal to ExceptionSectionID.
|
2022-11-26 14:24:38 -08:00
|
|
|
std::optional<MBBSectionID> EHPadsSectionID;
|
2020-03-16 15:56:02 -07:00
|
|
|
|
|
|
|
for (auto &MBB : MF) {
|
2020-04-13 12:14:42 -07:00
|
|
|
// With the 'all' option, every basic block is placed in a unique section.
|
|
|
|
// With the 'list' option, every basic block is placed in a section
|
|
|
|
// associated with its cluster, unless we want individual unique sections
|
|
|
|
// for every basic block in this function (if FuncBBClusterInfo is empty).
|
|
|
|
if (MF.getTarget().getBBSectionsType() == llvm::BasicBlockSection::All ||
|
|
|
|
FuncBBClusterInfo.empty()) {
|
|
|
|
// If unique sections are desired for all basic blocks of the function, we
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
// set every basic block's section ID equal to its original position in
|
|
|
|
// the layout (which is equal to its number). This ensures that basic
|
|
|
|
// blocks are ordered canonically.
|
|
|
|
MBB.setSectionID(MBB.getNumber());
|
|
|
|
} else {
|
|
|
|
// TODO: Replace `getBBIDOrNumber` with `getBBID` once version 1 is
|
|
|
|
// deprecated.
|
|
|
|
auto I = FuncBBClusterInfo.find(MBB.getBBIDOrNumber());
|
|
|
|
if (I != FuncBBClusterInfo.end()) {
|
|
|
|
MBB.setSectionID(I->second.ClusterID);
|
|
|
|
} else {
|
|
|
|
// BB goes into the special cold section if it is not specified in the
|
|
|
|
// cluster info map.
|
|
|
|
MBB.setSectionID(MBBSectionID::ColdSectionID);
|
|
|
|
}
|
2020-03-16 15:56:02 -07:00
|
|
|
}
|
2020-04-13 12:14:42 -07:00
|
|
|
|
|
|
|
if (MBB.isEHPad() && EHPadsSectionID != MBB.getSectionID() &&
|
|
|
|
EHPadsSectionID != MBBSectionID::ExceptionSectionID) {
|
|
|
|
// If we already have one cluster containing eh_pads, this must be updated
|
|
|
|
// to ExceptionSectionID. Otherwise, we set it equal to the current
|
|
|
|
// section ID.
|
2022-06-26 18:31:51 -07:00
|
|
|
EHPadsSectionID = EHPadsSectionID ? MBBSectionID::ExceptionSectionID
|
|
|
|
: MBB.getSectionID();
|
2020-03-16 15:56:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// If EHPads are in more than one section, this places all of them in the
|
|
|
|
// special exception section.
|
|
|
|
if (EHPadsSectionID == MBBSectionID::ExceptionSectionID)
|
|
|
|
for (auto &MBB : MF)
|
2020-03-16 15:56:02 -07:00
|
|
|
if (MBB.isEHPad())
|
2022-06-20 22:45:45 -07:00
|
|
|
MBB.setSectionID(*EHPadsSectionID);
|
2020-08-05 15:34:31 -07:00
|
|
|
}
|
2020-04-13 12:14:42 -07:00
|
|
|
|
2020-08-05 15:34:31 -07:00
|
|
|
void llvm::sortBasicBlocksAndUpdateBranches(
|
|
|
|
MachineFunction &MF, MachineBasicBlockComparator MBBCmp) {
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
[[maybe_unused]] const MachineBasicBlock *EntryBlock = &MF.front();
|
|
|
|
SmallVector<MachineBasicBlock *> PreLayoutFallThroughs(MF.getNumBlockIDs());
|
2020-04-13 12:14:42 -07:00
|
|
|
for (auto &MBB : MF)
|
|
|
|
PreLayoutFallThroughs[MBB.getNumber()] = MBB.getFallThrough();
|
|
|
|
|
2020-08-05 15:34:31 -07:00
|
|
|
MF.sort(MBBCmp);
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
assert(&MF.front() == EntryBlock &&
|
|
|
|
"Entry block should not be displaced by basic block sections");
|
2020-08-05 15:34:31 -07:00
|
|
|
|
|
|
|
// Set IsBeginSection and IsEndSection according to the assigned section IDs.
|
|
|
|
MF.assignBeginEndSections();
|
|
|
|
|
|
|
|
// After reordering basic blocks, we must update basic block branches to
|
|
|
|
// insert explicit fallthrough branches when required and optimize branches
|
|
|
|
// when possible.
|
|
|
|
updateBranches(MF, PreLayoutFallThroughs);
|
|
|
|
}
|
|
|
|
|
Exception support for basic block sections
This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here: https://groups.google.com/forum/#!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here: https://github.com/google/llvm-propeller/blob/plo-dev/Propeller_RFC.pdf
This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a **nop** operation as the first non-CFI instruction in the exception section.
**Background on Exception Handling in C++ ABI**
https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.
The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:
| CallSite | --> Position of the call site (relative to the function entry)
| CallSite length | --> Length of the call site.
| Landing Pad | --> Position of the landing pad (relative to the landing pad fragment’s begin label)
| Action record offset | --> Position of the first action record
The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative to the start of the function (as captured in the unwind table).
The landing pad entry is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.
The action record offset is an index into the action table which includes information about which exception types are caught.
**C++ Exceptions with Basic Block Sections**
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. Furthermore, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the range of call-sites for that section.
This patch introduces a new **CallSiteRange** structure which specifies the range of call-sites which correspond to every section:
`struct CallSiteRange {
// Symbol marking the beginning of the precedure fragment.
MCSymbol *FragmentBeginLabel = nullptr;
// Symbol marking the end of the procedure fragment.
MCSymbol *FragmentEndLabel = nullptr;
// LSDA symbol for this call-site range.
MCSymbol *ExceptionLabel = nullptr;
// Index of the first call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteBeginIdx = 0;
// Index just after the last call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteEndIdx = 0;
// Whether this is the call-site range containing all the landing pads.
bool IsLPRange = false;
};`
With N basic-block-sections, the call-site table is partitioned into N call-site ranges.
Conceptually, we emit the call-site ranges for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site ranges (denoted by LSDA1 and LSDA2) placed next to each other. However, their call-sites will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site range in order to place the call site ranges in separate LSDAs. We note that with -basic-block-sections, The CallSiteTableLength will not actually represent the length of the call site table, but rather the reference to the action table. Since the only purpose of this field is to locate the action table, correctness is guaranteed.
Finally, every call site range has one @LPStart pointer so the landing pads of each section must all reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section (hence the `IsLPRange` field in CallSiteRange).
| @LPStart | ---> Landing pad fragment ( LSDA1 points here)
| CallSite Table Length | ---> Used to find the action table.
| CallSites |
| … |
| … |
| @LPStart | ---> Landing pad fragment ( LSDA2 points here)
| CallSite Table Length |
| CallSites |
| … |
| … |
…
…
| Action Table |
| Types Table |
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D73739
2020-09-30 10:37:00 -07:00
|
|
|
// If the exception section begins with a landing pad, that landing pad will
|
|
|
|
// assume a zero offset (relative to @LPStart) in the LSDA. However, a value of
|
|
|
|
// zero implies "no landing pad." This function inserts a NOP just before the EH
|
Add a nop instruction if a section starts with landing pad for function splitter
This change adds a nop instruction if section starts with landing pad. This change is like [D73739](https://reviews.llvm.org/D73739) which avoids zero offset landing pad in basic block sections.
Detailed description:
The current machine functions splitter can create ˜sections which start with a landing pad themselves. This places landing pad at offset zero from LPStart.
```
.section .text.split.foo10,"ax",@progbits
foo10.cold: # %lpad
.cfi_startproc
.cfi_personality 3, __gxx_personality_v0
.cfi_lsda 3, .Lexception5
.cfi_def_cfa %rsp, 16
.Ltmp11: <--- This is a Landing pad and also LP Start as it is start of this section
movq %rax, %rdi <--- first instruction is at offest 0 from LPStart
callq _Unwind_Resume@PLT
```
This will cause landing pad entries to become zero (.Ltmp11-foo10.cold)
```
.Lcst_begin4:
.uleb128 .Ltmp9-.Lfunc_begin2 # >> Call Site 1 <<
.uleb128 .Ltmp10-.Ltmp9 # Call between .Ltmp9 and .Ltmp10
.uleb128 .Ltmp11-foo10.cold <---This is zero # jumps to .Ltmp11
.byte 3 # On action: 2
.uleb128 .Ltmp10-.Lfunc_begin2 # >> Call Site 2 <<
.uleb128 .Lfunc_end9-.Ltmp10 # Call between .Ltmp10 and .Lfunc_end9
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.p2align 2
```
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. This change adds a nop instruction at start of such sections so that such a case could be avoided. Output:
```
.section .text.split.foo10,"ax",@progbits
foo10.cold: # %lpad
.cfi_startproc
.cfi_personality 3, __gxx_personality_v0
.cfi_lsda 3, .Lexception5
.cfi_def_cfa %rsp, 16
nop <--- new instruction that is added
.Ltmp11:
movq %rax, %rdi
callq _Unwind_Resume@PLT
```
Reviewed By: modimo, snehasish, rahmanl
Differential Revision: https://reviews.llvm.org/D130133
2022-07-22 15:02:16 -07:00
|
|
|
// pad label to ensure a nonzero offset.
|
|
|
|
void llvm::avoidZeroOffsetLandingPad(MachineFunction &MF) {
|
Exception support for basic block sections
This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here: https://groups.google.com/forum/#!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here: https://github.com/google/llvm-propeller/blob/plo-dev/Propeller_RFC.pdf
This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a **nop** operation as the first non-CFI instruction in the exception section.
**Background on Exception Handling in C++ ABI**
https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.
The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:
| CallSite | --> Position of the call site (relative to the function entry)
| CallSite length | --> Length of the call site.
| Landing Pad | --> Position of the landing pad (relative to the landing pad fragment’s begin label)
| Action record offset | --> Position of the first action record
The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative to the start of the function (as captured in the unwind table).
The landing pad entry is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.
The action record offset is an index into the action table which includes information about which exception types are caught.
**C++ Exceptions with Basic Block Sections**
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. Furthermore, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the range of call-sites for that section.
This patch introduces a new **CallSiteRange** structure which specifies the range of call-sites which correspond to every section:
`struct CallSiteRange {
// Symbol marking the beginning of the precedure fragment.
MCSymbol *FragmentBeginLabel = nullptr;
// Symbol marking the end of the procedure fragment.
MCSymbol *FragmentEndLabel = nullptr;
// LSDA symbol for this call-site range.
MCSymbol *ExceptionLabel = nullptr;
// Index of the first call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteBeginIdx = 0;
// Index just after the last call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteEndIdx = 0;
// Whether this is the call-site range containing all the landing pads.
bool IsLPRange = false;
};`
With N basic-block-sections, the call-site table is partitioned into N call-site ranges.
Conceptually, we emit the call-site ranges for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site ranges (denoted by LSDA1 and LSDA2) placed next to each other. However, their call-sites will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site range in order to place the call site ranges in separate LSDAs. We note that with -basic-block-sections, The CallSiteTableLength will not actually represent the length of the call site table, but rather the reference to the action table. Since the only purpose of this field is to locate the action table, correctness is guaranteed.
Finally, every call site range has one @LPStart pointer so the landing pads of each section must all reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section (hence the `IsLPRange` field in CallSiteRange).
| @LPStart | ---> Landing pad fragment ( LSDA1 points here)
| CallSite Table Length | ---> Used to find the action table.
| CallSites |
| … |
| … |
| @LPStart | ---> Landing pad fragment ( LSDA2 points here)
| CallSite Table Length |
| CallSites |
| … |
| … |
…
…
| Action Table |
| Types Table |
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D73739
2020-09-30 10:37:00 -07:00
|
|
|
for (auto &MBB : MF) {
|
|
|
|
if (MBB.isBeginSection() && MBB.isEHPad()) {
|
|
|
|
MachineBasicBlock::iterator MI = MBB.begin();
|
|
|
|
while (!MI->isEHLabel())
|
|
|
|
++MI;
|
2021-03-15 12:05:33 -07:00
|
|
|
MCInst Nop = MF.getSubtarget().getInstrInfo()->getNop();
|
Exception support for basic block sections
This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here: https://groups.google.com/forum/#!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here: https://github.com/google/llvm-propeller/blob/plo-dev/Propeller_RFC.pdf
This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a **nop** operation as the first non-CFI instruction in the exception section.
**Background on Exception Handling in C++ ABI**
https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.
The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:
| CallSite | --> Position of the call site (relative to the function entry)
| CallSite length | --> Length of the call site.
| Landing Pad | --> Position of the landing pad (relative to the landing pad fragment’s begin label)
| Action record offset | --> Position of the first action record
The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative to the start of the function (as captured in the unwind table).
The landing pad entry is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.
The action record offset is an index into the action table which includes information about which exception types are caught.
**C++ Exceptions with Basic Block Sections**
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. Furthermore, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the range of call-sites for that section.
This patch introduces a new **CallSiteRange** structure which specifies the range of call-sites which correspond to every section:
`struct CallSiteRange {
// Symbol marking the beginning of the precedure fragment.
MCSymbol *FragmentBeginLabel = nullptr;
// Symbol marking the end of the procedure fragment.
MCSymbol *FragmentEndLabel = nullptr;
// LSDA symbol for this call-site range.
MCSymbol *ExceptionLabel = nullptr;
// Index of the first call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteBeginIdx = 0;
// Index just after the last call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteEndIdx = 0;
// Whether this is the call-site range containing all the landing pads.
bool IsLPRange = false;
};`
With N basic-block-sections, the call-site table is partitioned into N call-site ranges.
Conceptually, we emit the call-site ranges for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site ranges (denoted by LSDA1 and LSDA2) placed next to each other. However, their call-sites will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site range in order to place the call site ranges in separate LSDAs. We note that with -basic-block-sections, The CallSiteTableLength will not actually represent the length of the call site table, but rather the reference to the action table. Since the only purpose of this field is to locate the action table, correctness is guaranteed.
Finally, every call site range has one @LPStart pointer so the landing pads of each section must all reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section (hence the `IsLPRange` field in CallSiteRange).
| @LPStart | ---> Landing pad fragment ( LSDA1 points here)
| CallSite Table Length | ---> Used to find the action table.
| CallSites |
| … |
| … |
| @LPStart | ---> Landing pad fragment ( LSDA2 points here)
| CallSite Table Length |
| CallSites |
| … |
| … |
…
…
| Action Table |
| Types Table |
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D73739
2020-09-30 10:37:00 -07:00
|
|
|
BuildMI(MBB, MI, DebugLoc(),
|
2021-03-15 12:05:33 -07:00
|
|
|
MF.getSubtarget().getInstrInfo()->get(Nop.getOpcode()));
|
Exception support for basic block sections
This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here: https://groups.google.com/forum/#!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here: https://github.com/google/llvm-propeller/blob/plo-dev/Propeller_RFC.pdf
This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a **nop** operation as the first non-CFI instruction in the exception section.
**Background on Exception Handling in C++ ABI**
https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.
The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:
| CallSite | --> Position of the call site (relative to the function entry)
| CallSite length | --> Length of the call site.
| Landing Pad | --> Position of the landing pad (relative to the landing pad fragment’s begin label)
| Action record offset | --> Position of the first action record
The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative to the start of the function (as captured in the unwind table).
The landing pad entry is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.
The action record offset is an index into the action table which includes information about which exception types are caught.
**C++ Exceptions with Basic Block Sections**
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. Furthermore, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the range of call-sites for that section.
This patch introduces a new **CallSiteRange** structure which specifies the range of call-sites which correspond to every section:
`struct CallSiteRange {
// Symbol marking the beginning of the precedure fragment.
MCSymbol *FragmentBeginLabel = nullptr;
// Symbol marking the end of the procedure fragment.
MCSymbol *FragmentEndLabel = nullptr;
// LSDA symbol for this call-site range.
MCSymbol *ExceptionLabel = nullptr;
// Index of the first call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteBeginIdx = 0;
// Index just after the last call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteEndIdx = 0;
// Whether this is the call-site range containing all the landing pads.
bool IsLPRange = false;
};`
With N basic-block-sections, the call-site table is partitioned into N call-site ranges.
Conceptually, we emit the call-site ranges for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site ranges (denoted by LSDA1 and LSDA2) placed next to each other. However, their call-sites will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site range in order to place the call site ranges in separate LSDAs. We note that with -basic-block-sections, The CallSiteTableLength will not actually represent the length of the call site table, but rather the reference to the action table. Since the only purpose of this field is to locate the action table, correctness is guaranteed.
Finally, every call site range has one @LPStart pointer so the landing pads of each section must all reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section (hence the `IsLPRange` field in CallSiteRange).
| @LPStart | ---> Landing pad fragment ( LSDA1 points here)
| CallSite Table Length | ---> Used to find the action table.
| CallSites |
| … |
| … |
| @LPStart | ---> Landing pad fragment ( LSDA2 points here)
| CallSite Table Length |
| CallSites |
| … |
| … |
…
…
| Action Table |
| Types Table |
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D73739
2020-09-30 10:37:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-29 18:47:26 -08:00
|
|
|
// This checks if the source of this function has drifted since this binary was
|
|
|
|
// profiled previously. For now, we are piggy backing on what PGO does to
|
|
|
|
// detect this with instrumented profiles. PGO emits an hash of the IR and
|
|
|
|
// checks if the hash has changed. Advanced basic block layout is usually done
|
|
|
|
// on top of PGO optimized binaries and hence this check works well in practice.
|
|
|
|
static bool hasInstrProfHashMismatch(MachineFunction &MF) {
|
|
|
|
if (!BBSectionsDetectSourceDrift)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const char MetadataName[] = "instr_prof_hash_mismatch";
|
|
|
|
auto *Existing = MF.getFunction().getMetadata(LLVMContext::MD_annotation);
|
|
|
|
if (Existing) {
|
|
|
|
MDTuple *Tuple = cast<MDTuple>(Existing);
|
2022-07-17 01:33:28 -07:00
|
|
|
for (const auto &N : Tuple->operands())
|
2021-01-29 18:47:26 -08:00
|
|
|
if (cast<MDString>(N.get())->getString() == MetadataName)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-05 15:34:31 -07:00
|
|
|
bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) {
|
|
|
|
auto BBSectionsType = MF.getTarget().getBBSectionsType();
|
|
|
|
assert(BBSectionsType != BasicBlockSection::None &&
|
|
|
|
"BB Sections not enabled!");
|
2021-01-29 18:47:26 -08:00
|
|
|
|
|
|
|
// Check for source drift. If the source has changed since the profiles
|
|
|
|
// were obtained, optimizing basic blocks might be sub-optimal.
|
|
|
|
// This only applies to BasicBlockSection::List as it creates
|
|
|
|
// clusters of basic blocks using basic block ids. Source drift can
|
|
|
|
// invalidate these groupings leading to sub-optimal code generation with
|
|
|
|
// regards to performance.
|
|
|
|
if (BBSectionsType == BasicBlockSection::List &&
|
|
|
|
hasInstrProfHashMismatch(MF))
|
|
|
|
return true;
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
// Renumber blocks before sorting them. This is useful during sorting,
|
|
|
|
// basic blocks in the same section will retain the default order.
|
|
|
|
// This renumbering should also be done for basic block labels to match the
|
|
|
|
// profiles with the correct blocks.
|
|
|
|
// For LLVM_BB_ADDR_MAP versions 2 and higher, this renumbering serves
|
|
|
|
// the different purpose of accessing the original layout positions and
|
|
|
|
// finding the original fallthroughs.
|
|
|
|
// TODO: Change the above comment accordingly when version 1 is deprecated.
|
2020-08-05 15:34:31 -07:00
|
|
|
MF.RenumberBlocks();
|
|
|
|
|
|
|
|
if (BBSectionsType == BasicBlockSection::Labels) {
|
|
|
|
MF.setBBSectionsType(BBSectionsType);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-26 19:27:05 -07:00
|
|
|
BBSectionsProfileReader = &getAnalysis<BasicBlockSectionsProfileReader>();
|
|
|
|
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
// Map from BBID of blocks to their cluster information.
|
|
|
|
DenseMap<unsigned, BBClusterInfo> FuncBBClusterInfo;
|
2020-08-05 15:34:31 -07:00
|
|
|
if (BBSectionsType == BasicBlockSection::List &&
|
2022-05-26 19:27:05 -07:00
|
|
|
!getBBClusterInfoForFunction(MF, BBSectionsProfileReader,
|
2020-08-05 15:34:31 -07:00
|
|
|
FuncBBClusterInfo))
|
|
|
|
return true;
|
|
|
|
MF.setBBSectionsType(BBSectionsType);
|
|
|
|
assignSections(MF, FuncBBClusterInfo);
|
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// We make sure that the cluster including the entry basic block precedes all
|
|
|
|
// other clusters.
|
|
|
|
auto EntryBBSectionID = MF.front().getSectionID();
|
|
|
|
|
|
|
|
// Helper function for ordering BB sections as follows:
|
|
|
|
// * Entry section (section including the entry block).
|
|
|
|
// * Regular sections (in increasing order of their Number).
|
|
|
|
// ...
|
|
|
|
// * Exception section
|
|
|
|
// * Cold section
|
|
|
|
auto MBBSectionOrder = [EntryBBSectionID](const MBBSectionID &LHS,
|
|
|
|
const MBBSectionID &RHS) {
|
|
|
|
// We make sure that the section containing the entry block precedes all the
|
|
|
|
// other sections.
|
|
|
|
if (LHS == EntryBBSectionID || RHS == EntryBBSectionID)
|
|
|
|
return LHS == EntryBBSectionID;
|
|
|
|
return LHS.Type == RHS.Type ? LHS.Number < RHS.Number : LHS.Type < RHS.Type;
|
|
|
|
};
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-04-13 12:14:42 -07:00
|
|
|
// We sort all basic blocks to make sure the basic blocks of every cluster are
|
|
|
|
// contiguous and ordered accordingly. Furthermore, clusters are ordered in
|
|
|
|
// increasing order of their section IDs, with the exception and the
|
|
|
|
// cold section placed at the end of the function.
|
2020-08-05 15:34:31 -07:00
|
|
|
auto Comparator = [&](const MachineBasicBlock &X,
|
|
|
|
const MachineBasicBlock &Y) {
|
2020-04-13 12:14:42 -07:00
|
|
|
auto XSectionID = X.getSectionID();
|
|
|
|
auto YSectionID = Y.getSectionID();
|
|
|
|
if (XSectionID != YSectionID)
|
|
|
|
return MBBSectionOrder(XSectionID, YSectionID);
|
|
|
|
// If the two basic block are in the same section, the order is decided by
|
|
|
|
// their position within the section.
|
|
|
|
if (XSectionID.Type == MBBSectionID::SectionType::Default)
|
[Propeller] Use Fixed MBB ID instead of volatile MachineBasicBlock::Number.
Let Propeller use specialized IDs for basic blocks, instead of MBB number.
This allows optimizations not just prior to asm-printer, but throughout the entire codegen.
This patch only implements the functionality under the new `LLVM_BB_ADDR_MAP` version, but the old version is still being used. A later patch will change the used version.
####Background
Today Propeller uses machine basic block (MBB) numbers, which already exist, to map native assembly to machine IR. This is done as follows.
- Basic block addresses are captured and dumped into the `LLVM_BB_ADDR_MAP` section just before the AsmPrinter pass which writes out object files. This ensures that we have a mapping that is close to assembly.
- Profiling mapping works by taking a virtual address of an instruction and looking up the `LLVM_BB_ADDR_MAP` section to find the MBB number it corresponds to.
- While this works well today, we need to do better when we scale Propeller to target other Machine IR optimizations like spill code optimization. Register allocation happens earlier in the Machine IR pipeline and we need an annotation mechanism that is valid at that point.
- The current scheme will not work in this scenario because the MBB number of a particular basic block is not fixed and changes over the course of codegen (via renumbering, adding, and removing the basic blocks).
- In other words, the volatile MBB numbers do not provide a one-to-one correspondence throughout the lifetime of Machine IR. Profile annotation using MBB numbers is restricted to a fixed point; only valid at the exact point where it was dumped.
- Further, the object file can only be dumped before AsmPrinter and cannot be dumped at an arbitrary point in the Machine IR pass pipeline. Hence, MBB numbers are not suitable and we need something else.
####Solution
We propose using fixed unique incremental MBB IDs for basic blocks instead of volatile MBB numbers. These IDs are assigned upon the creation of machine basic blocks. We modify `MachineFunction::CreateMachineBasicBlock` to assign the fixed ID to every newly created basic block. It assigns `MachineFunction::NextMBBID` to the MBB ID and then increments it, which ensures having unique IDs.
To ensure correct profile attribution, multiple equivalent compilations must generate the same Propeller IDs. This is guaranteed as long as the MachineFunction passes run in the same order. Since the `NextBBID` variable is scoped to `MachineFunction`, interleaving of codegen for different functions won't cause any inconsistencies.
The new encoding is generated under the new version number 2 and we keep backward-compatibility with older versions.
####Impact on Size of the `LLVM_BB_ADDR_MAP` Section
Emitting the Propeller ID results in a 23% increase in the size of the `LLVM_BB_ADDR_MAP` section for the clang binary.
Reviewed By: tmsriram
Differential Revision: https://reviews.llvm.org/D100808
2022-12-06 22:37:33 -08:00
|
|
|
return FuncBBClusterInfo.lookup(X.getBBIDOrNumber()).PositionInCluster <
|
|
|
|
FuncBBClusterInfo.lookup(Y.getBBIDOrNumber()).PositionInCluster;
|
2020-04-13 12:14:42 -07:00
|
|
|
return X.getNumber() < Y.getNumber();
|
2020-08-05 15:34:31 -07:00
|
|
|
};
|
2020-03-16 15:56:02 -07:00
|
|
|
|
2020-08-05 15:34:31 -07:00
|
|
|
sortBasicBlocksAndUpdateBranches(MF, Comparator);
|
Exception support for basic block sections
This is part of the Propeller framework to do post link code layout optimizations. Please see the RFC here: https://groups.google.com/forum/#!msg/llvm-dev/ef3mKzAdJ7U/1shV64BYBAAJ and the detailed RFC doc here: https://github.com/google/llvm-propeller/blob/plo-dev/Propeller_RFC.pdf
This patch provides exception support for basic block sections by splitting the call-site table into call-site ranges corresponding to different basic block sections. Still all landing pads must reside in the same basic block section (which is guaranteed by the the core basic block section patch D73674 (ExceptionSection) ). Each call-site table will refer to the landing pad fragment by explicitly specifying @LPstart (which is omitted in the normal non-basic-block section case). All these call-site tables will share their action and type tables.
The C++ ABI somehow assumes that no landing pads point directly to LPStart (which works in the normal case since the function begin is never a landing pad), and uses LP.offset = 0 to specify no landing pad. In the case of basic block section where one section contains all the landing pads, the landing pad offset relative to LPStart could actually be zero. Thus, we avoid zero-offset landing pads by inserting a **nop** operation as the first non-CFI instruction in the exception section.
**Background on Exception Handling in C++ ABI**
https://github.com/itanium-cxx-abi/cxx-abi/blob/master/exceptions.pdf
Compiler emits an exception table for every function. When an exception is thrown, the stack unwinding library queries the unwind table (which includes the start and end of each function) to locate the exception table for that function.
The exception table includes a call site table for the function, which is used to guide the exception handling runtime to take the appropriate action upon an exception. Each call site record in this table is structured as follows:
| CallSite | --> Position of the call site (relative to the function entry)
| CallSite length | --> Length of the call site.
| Landing Pad | --> Position of the landing pad (relative to the landing pad fragment’s begin label)
| Action record offset | --> Position of the first action record
The call site records partition a function into different pieces and describe what action must be taken for each callsite. The callsite fields are relative to the start of the function (as captured in the unwind table).
The landing pad entry is a reference into the function and corresponds roughly to the catch block of a try/catch statement. When execution resumes at a landing pad, it receives an exception structure and a selector value corresponding to the type of the exception thrown, and executes similar to a switch-case statement. The landing pad field is relative to the beginning of the procedure fragment which includes all the landing pads (@LPStart). The C++ ABI requires all landing pads to be in the same fragment. Nonetheless, without basic block sections, @LPStart is the same as the function @Start (found in the unwind table) and can be omitted.
The action record offset is an index into the action table which includes information about which exception types are caught.
**C++ Exceptions with Basic Block Sections**
Basic block sections break the contiguity of a function fragment. Therefore, call sites must be specified relative to the beginning of the basic block section. Furthermore, the unwinding library should be able to find the corresponding callsites for each section. To do so, the .cfi_lsda directive for a section must point to the range of call-sites for that section.
This patch introduces a new **CallSiteRange** structure which specifies the range of call-sites which correspond to every section:
`struct CallSiteRange {
// Symbol marking the beginning of the precedure fragment.
MCSymbol *FragmentBeginLabel = nullptr;
// Symbol marking the end of the procedure fragment.
MCSymbol *FragmentEndLabel = nullptr;
// LSDA symbol for this call-site range.
MCSymbol *ExceptionLabel = nullptr;
// Index of the first call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteBeginIdx = 0;
// Index just after the last call-site entry in the call-site table which
// belongs to this range.
size_t CallSiteEndIdx = 0;
// Whether this is the call-site range containing all the landing pads.
bool IsLPRange = false;
};`
With N basic-block-sections, the call-site table is partitioned into N call-site ranges.
Conceptually, we emit the call-site ranges for sections sequentially in the exception table as if each section has its own exception table. In the example below, two sections result in the two call site ranges (denoted by LSDA1 and LSDA2) placed next to each other. However, their call-sites will refer to records in the shared Action Table. We also emit the header fields (@LPStart and CallSite Table Length) for each call site range in order to place the call site ranges in separate LSDAs. We note that with -basic-block-sections, The CallSiteTableLength will not actually represent the length of the call site table, but rather the reference to the action table. Since the only purpose of this field is to locate the action table, correctness is guaranteed.
Finally, every call site range has one @LPStart pointer so the landing pads of each section must all reside in one section (not necessarily the same section). To make this easier, we decide to place all landing pads of the function in one section (hence the `IsLPRange` field in CallSiteRange).
| @LPStart | ---> Landing pad fragment ( LSDA1 points here)
| CallSite Table Length | ---> Used to find the action table.
| CallSites |
| … |
| … |
| @LPStart | ---> Landing pad fragment ( LSDA2 points here)
| CallSite Table Length |
| CallSites |
| … |
| … |
…
…
| Action Table |
| Types Table |
Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D73739
2020-09-30 10:37:00 -07:00
|
|
|
avoidZeroOffsetLandingPad(MF);
|
2020-03-16 15:56:02 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-05 17:11:48 -07:00
|
|
|
void BasicBlockSections::getAnalysisUsage(AnalysisUsage &AU) const {
|
2020-03-16 15:56:02 -07:00
|
|
|
AU.setPreservesAll();
|
2022-05-26 19:27:05 -07:00
|
|
|
AU.addRequired<BasicBlockSectionsProfileReader>();
|
2020-06-30 19:10:01 -07:00
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
2020-03-16 15:56:02 -07:00
|
|
|
}
|
|
|
|
|
2022-05-26 19:27:05 -07:00
|
|
|
MachineFunctionPass *llvm::createBasicBlockSectionsPass() {
|
|
|
|
return new BasicBlockSections();
|
2020-03-16 15:56:02 -07:00
|
|
|
}
|