llvm/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h

//===- WholeProgramDevirt.h - Whole-program devirt pass ---------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines parts of the whole-program devirtualization pass
// implementation that may be usefully unit tested.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H
#define LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H

#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/PassManager.h"
#include <cassert>
#include <cstdint>
#include <map>
#include <set>
#include <utility>
#include <vector>

namespace llvm {
class Module;

template <typename T> class ArrayRef;
template <typename T> class MutableArrayRef;
class GlobalVariable;
class ModuleSummaryIndex;
struct ValueInfo;

namespace wholeprogramdevirt {

// A bit vector that keeps track of which bits are used. We use this to
// pack constant values compactly before and after each virtual table.
struct AccumBitVector {};

// The bits that will be stored before and after a particular vtable.
struct VTableBits {};

// Information about a member of a particular type identifier.
struct TypeMemberInfo {};

// A virtual call target, i.e. an entry in a particular vtable.
struct VirtualCallTarget {};

// Find the minimum offset that we may store a value of size Size bits at. If
// IsAfter is set, look for an offset before the object, otherwise look for an
// offset after the object.
uint64_t findLowestOffset(ArrayRef<VirtualCallTarget> Targets, bool IsAfter,
                          uint64_t Size);

// Set the stored value in each of Targets to VirtualCallTarget::RetVal at the
// given allocation offset before the vtable address. Stores the computed
// byte/bit offset to OffsetByte/OffsetBit.
void setBeforeReturnValues(MutableArrayRef<VirtualCallTarget> Targets,
                           uint64_t AllocBefore, unsigned BitWidth,
                           int64_t &OffsetByte, uint64_t &OffsetBit);

// Set the stored value in each of Targets to VirtualCallTarget::RetVal at the
// given allocation offset after the vtable address. Stores the computed
// byte/bit offset to OffsetByte/OffsetBit.
void setAfterReturnValues(MutableArrayRef<VirtualCallTarget> Targets,
                          uint64_t AllocAfter, unsigned BitWidth,
                          int64_t &OffsetByte, uint64_t &OffsetBit);

} // end namespace wholeprogramdevirt

struct WholeProgramDevirtPass : public PassInfoMixin<WholeProgramDevirtPass> {};

struct VTableSlotSummary {};
bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO);
void updatePublicTypeTestCalls(Module &M,
                               bool WholeProgramVisibilityEnabledInLTO);
void updateVCallVisibilityInModule(
    Module &M, bool WholeProgramVisibilityEnabledInLTO,
    const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
    bool ValidateAllVtablesHaveTypeInfos,
    function_ref<bool(StringRef)> IsVisibleToRegularObj);
void updateVCallVisibilityInIndex(
    ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO,
    const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
    const DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols);

void getVisibleToRegularObjVtableGUIDs(
    ModuleSummaryIndex &Index,
    DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols,
    function_ref<bool(StringRef)> IsVisibleToRegularObj);

/// Perform index-based whole program devirtualization on the \p Summary
/// index. Any devirtualized targets used by a type test in another module
/// are added to the \p ExportedGUIDs set. For any local devirtualized targets
/// only used within the defining module, the information necessary for
/// locating the corresponding WPD resolution is recorded for the ValueInfo
/// in case it is exported by cross module importing (in which case the
/// devirtualized target name will need adjustment).
void runWholeProgramDevirtOnIndex(
    ModuleSummaryIndex &Summary, std::set<GlobalValue::GUID> &ExportedGUIDs,
    std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap);

/// Call after cross-module importing to update the recorded single impl
/// devirt target names for any locals that were exported.
void updateIndexWPDForExports(
    ModuleSummaryIndex &Summary,
    function_ref<bool(StringRef, ValueInfo)> isExported,
    std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap);

} // end namespace llvm

#endif // LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H