1//===- InstructionNamer.cpp - Give anonymous instructions names -----------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This is a little utility pass that gives instructions names, this is mostly
10// useful when diffing the effect of an optimization because deleting an
11// unnamed instruction can change all other instruction numbering, making the
12// diff very noisy.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/Transforms/Utils/InstructionNamer.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/Analysis/LazyCallGraph.h"
19#include "llvm/Analysis/LoopInfo.h"
20#include "llvm/IR/Function.h"
21#include "llvm/IR/Module.h"
22#include "llvm/IR/PassInstrumentation.h"
23#include "llvm/IR/PassManager.h"
24#include "llvm/IR/Type.h"
25#include <cstdint>
26#include <string>
27
28using namespace llvm;
29
30static void nameInstructions(Function &F, uint64_t *NextID = nullptr) {
31 auto getName = [NextID](StringRef Prefix) -> std::string {
32 if (!NextID)
33 return Prefix.str();
34 return (Twine(Prefix) + "." + Twine((*NextID)++)).str();
35 };
36
37 for (Argument &Arg : F.args()) {
38 if (!Arg.hasName())
39 Arg.setName(getName("arg"));
40 }
41
42 for (BasicBlock &BB : F) {
43 if (!BB.hasName())
44 BB.setName(getName("bb"));
45
46 for (Instruction &I : BB) {
47 if (!I.hasName() && !I.getType()->isVoidTy())
48 I.setName(getName("i"));
49 }
50 }
51}
52
53PreservedAnalyses InstructionNamerPass::run(Function &F,
54 FunctionAnalysisManager &FAM) {
55 nameInstructions(F);
56 return PreservedAnalyses::all();
57}
58
59static void nameIRUnit(IRUnitRef IR, uint64_t &NextID) {
60 if (const auto *M = dyn_cast<Module>(Val&: IR)) {
61 for (Function &F : *const_cast<Module *>(M))
62 nameInstructions(F, NextID: &NextID);
63 } else if (const auto *F = dyn_cast<Function>(Val&: IR)) {
64 nameInstructions(F&: *const_cast<Function *>(F), NextID: &NextID);
65 } else if (const auto *C = dyn_cast<LazyCallGraph::SCC>(Val&: IR)) {
66 for (const LazyCallGraph::Node &N : *C)
67 nameInstructions(F&: N.getFunction(), NextID: &NextID);
68 } else if (const auto *L = dyn_cast<Loop>(Val&: IR)) {
69 nameInstructions(F&: *L->getHeader()->getParent(), NextID: &NextID);
70 }
71}
72
73void InstructionNamerPass::registerCallbacks(PassInstrumentationCallbacks &PIC,
74 uint64_t &NextID) {
75 // The symbol table only detects collisions with live values. Keep an ID
76 // across callbacks so deleting a value does not reuse its generated ID.
77 PIC.registerBeforeNonSkippedPassCallback(
78 C: [&NextID](StringRef, IRUnitRef IR) { nameIRUnit(IR, NextID); });
79 PIC.registerAfterPassCallback(
80 C: [&NextID](StringRef, IRUnitRef IR, const PreservedAnalyses &) {
81 nameIRUnit(IR, NextID);
82 });
83}
84