File indexing completed on 2026-05-10 08:44:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H
0015 #define LLVM_TRANSFORMS_IPO_WHOLEPROGRAMDEVIRT_H
0016
0017 #include "llvm/ADT/DenseSet.h"
0018 #include "llvm/IR/GlobalValue.h"
0019 #include "llvm/IR/PassManager.h"
0020 #include <cassert>
0021 #include <cstdint>
0022 #include <map>
0023 #include <set>
0024 #include <utility>
0025 #include <vector>
0026
0027 namespace llvm {
0028 class Module;
0029
0030 template <typename T> class ArrayRef;
0031 template <typename T> class MutableArrayRef;
0032 class GlobalVariable;
0033 class ModuleSummaryIndex;
0034 struct ValueInfo;
0035
0036 namespace wholeprogramdevirt {
0037
0038
0039
0040 struct AccumBitVector {
0041 std::vector<uint8_t> Bytes;
0042
0043
0044 std::vector<uint8_t> BytesUsed;
0045
0046 std::pair<uint8_t *, uint8_t *> getPtrToData(uint64_t Pos, uint8_t Size) {
0047 if (Bytes.size() < Pos + Size) {
0048 Bytes.resize(Pos + Size);
0049 BytesUsed.resize(Pos + Size);
0050 }
0051 return std::make_pair(Bytes.data() + Pos, BytesUsed.data() + Pos);
0052 }
0053
0054
0055
0056 void setLE(uint64_t Pos, uint64_t Val, uint8_t Size) {
0057 assert(Pos % 8 == 0);
0058 auto DataUsed = getPtrToData(Pos / 8, Size);
0059 for (unsigned I = 0; I != Size; ++I) {
0060 DataUsed.first[I] = Val >> (I * 8);
0061 assert(!DataUsed.second[I]);
0062 DataUsed.second[I] = 0xff;
0063 }
0064 }
0065
0066
0067
0068 void setBE(uint64_t Pos, uint64_t Val, uint8_t Size) {
0069 assert(Pos % 8 == 0);
0070 auto DataUsed = getPtrToData(Pos / 8, Size);
0071 for (unsigned I = 0; I != Size; ++I) {
0072 DataUsed.first[Size - I - 1] = Val >> (I * 8);
0073 assert(!DataUsed.second[Size - I - 1]);
0074 DataUsed.second[Size - I - 1] = 0xff;
0075 }
0076 }
0077
0078
0079 void setBit(uint64_t Pos, bool b) {
0080 auto DataUsed = getPtrToData(Pos / 8, 1);
0081 if (b)
0082 *DataUsed.first |= 1 << (Pos % 8);
0083 assert(!(*DataUsed.second & (1 << Pos % 8)));
0084 *DataUsed.second |= 1 << (Pos % 8);
0085 }
0086 };
0087
0088
0089 struct VTableBits {
0090
0091 GlobalVariable *GV;
0092
0093
0094 uint64_t ObjectSize = 0;
0095
0096
0097
0098
0099
0100 AccumBitVector Before;
0101
0102
0103 AccumBitVector After;
0104 };
0105
0106
0107 struct TypeMemberInfo {
0108
0109 VTableBits *Bits;
0110
0111
0112 uint64_t Offset;
0113
0114 bool operator<(const TypeMemberInfo &other) const {
0115 return Bits < other.Bits || (Bits == other.Bits && Offset < other.Offset);
0116 }
0117 };
0118
0119
0120 struct VirtualCallTarget {
0121 VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM);
0122
0123
0124 VirtualCallTarget(const TypeMemberInfo *TM, bool IsBigEndian)
0125 : Fn(nullptr), TM(TM), IsBigEndian(IsBigEndian), WasDevirt(false) {}
0126
0127
0128 GlobalValue *Fn;
0129
0130
0131
0132 const TypeMemberInfo *TM;
0133
0134
0135
0136 uint64_t RetVal;
0137
0138
0139 bool IsBigEndian;
0140
0141
0142 bool WasDevirt;
0143
0144
0145
0146
0147
0148 uint64_t minBeforeBytes() const { return TM->Offset; }
0149
0150
0151
0152
0153
0154
0155 uint64_t minAfterBytes() const { return TM->Bits->ObjectSize - TM->Offset; }
0156
0157
0158
0159 uint64_t allocatedBeforeBytes() const {
0160 return minBeforeBytes() + TM->Bits->Before.Bytes.size();
0161 }
0162
0163
0164
0165 uint64_t allocatedAfterBytes() const {
0166 return minAfterBytes() + TM->Bits->After.Bytes.size();
0167 }
0168
0169
0170 void setBeforeBit(uint64_t Pos) {
0171 assert(Pos >= 8 * minBeforeBytes());
0172 TM->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal);
0173 }
0174
0175
0176 void setAfterBit(uint64_t Pos) {
0177 assert(Pos >= 8 * minAfterBytes());
0178 TM->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal);
0179 }
0180
0181
0182
0183
0184 void setBeforeBytes(uint64_t Pos, uint8_t Size) {
0185 assert(Pos >= 8 * minBeforeBytes());
0186 if (IsBigEndian)
0187 TM->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size);
0188 else
0189 TM->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size);
0190 }
0191
0192
0193 void setAfterBytes(uint64_t Pos, uint8_t Size) {
0194 assert(Pos >= 8 * minAfterBytes());
0195 if (IsBigEndian)
0196 TM->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size);
0197 else
0198 TM->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size);
0199 }
0200 };
0201
0202
0203
0204
0205 uint64_t findLowestOffset(ArrayRef<VirtualCallTarget> Targets, bool IsAfter,
0206 uint64_t Size);
0207
0208
0209
0210
0211 void setBeforeReturnValues(MutableArrayRef<VirtualCallTarget> Targets,
0212 uint64_t AllocBefore, unsigned BitWidth,
0213 int64_t &OffsetByte, uint64_t &OffsetBit);
0214
0215
0216
0217
0218 void setAfterReturnValues(MutableArrayRef<VirtualCallTarget> Targets,
0219 uint64_t AllocAfter, unsigned BitWidth,
0220 int64_t &OffsetByte, uint64_t &OffsetBit);
0221
0222 }
0223
0224 struct WholeProgramDevirtPass : public PassInfoMixin<WholeProgramDevirtPass> {
0225 ModuleSummaryIndex *ExportSummary;
0226 const ModuleSummaryIndex *ImportSummary;
0227 bool UseCommandLine = false;
0228 WholeProgramDevirtPass()
0229 : ExportSummary(nullptr), ImportSummary(nullptr), UseCommandLine(true) {}
0230 WholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary,
0231 const ModuleSummaryIndex *ImportSummary)
0232 : ExportSummary(ExportSummary), ImportSummary(ImportSummary) {
0233 assert(!(ExportSummary && ImportSummary));
0234 }
0235 PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
0236 };
0237
0238 struct VTableSlotSummary {
0239 StringRef TypeID;
0240 uint64_t ByteOffset;
0241 };
0242 bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO);
0243 void updatePublicTypeTestCalls(Module &M,
0244 bool WholeProgramVisibilityEnabledInLTO);
0245 void updateVCallVisibilityInModule(
0246 Module &M, bool WholeProgramVisibilityEnabledInLTO,
0247 const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
0248 bool ValidateAllVtablesHaveTypeInfos,
0249 function_ref<bool(StringRef)> IsVisibleToRegularObj);
0250 void updateVCallVisibilityInIndex(
0251 ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO,
0252 const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
0253 const DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols);
0254
0255 void getVisibleToRegularObjVtableGUIDs(
0256 ModuleSummaryIndex &Index,
0257 DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols,
0258 function_ref<bool(StringRef)> IsVisibleToRegularObj);
0259
0260
0261
0262
0263
0264
0265
0266
0267 void runWholeProgramDevirtOnIndex(
0268 ModuleSummaryIndex &Summary, std::set<GlobalValue::GUID> &ExportedGUIDs,
0269 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap);
0270
0271
0272
0273 void updateIndexWPDForExports(
0274 ModuleSummaryIndex &Summary,
0275 function_ref<bool(StringRef, ValueInfo)> isExported,
0276 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap);
0277
0278 }
0279
0280 #endif