LLVM: lib/Transforms/IPO/GlobalDCE.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

30

31using namespace llvm;

32

33#define DEBUG_TYPE "globaldce"

34

35namespace {

36class GlobalDCELegacyPass : public ModulePass {

37public:

38 static char ID;

41 }

42 bool runOnModule(Module &M) override {

43 if (skipModule(M))

44 return false;

45

46

48 auto PA = Impl.run(M, MAM);

49 return !PA.areAllPreserved();

50 }

51

52private:

54};

55}

56

57char GlobalDCELegacyPass::ID = 0;

58INITIALIZE_PASS(GlobalDCELegacyPass, "globaldce", "Dead Global Elimination",

59 false, false)

60

61

63

66 cl::desc("Enable virtual function elimination"));

67

68STATISTIC(NumAliases , "Number of global aliases removed");

69STATISTIC(NumFunctions, "Number of functions removed");

70STATISTIC(NumIFuncs, "Number of indirect functions removed");

71STATISTIC(NumVariables, "Number of global variables removed");

72STATISTIC(NumVFuncs, "Number of virtual functions removed");

73

74

76

77 if (F->isDeclaration())

78 return false;

80 for (auto &I : Entry) {

81 if (I.isDebugOrPseudoInst())

82 continue;

84 return !RI->getReturnValue();

85 break;

86 }

87 return false;

88}

89

90

91

92void GlobalDCEPass::ComputeDependencies(Value *V,

95 Function *Parent = I->getParent()->getParent();

100

101 auto [Where, Inserted] = ConstantDependenciesCache.try_emplace(CE);

102 SmallPtrSetImpl<GlobalValue *> &LocalDeps = Where->second;

103 if (Inserted) {

104 for (User *CEUser : CE->users())

105 ComputeDependencies(CEUser, LocalDeps);

106 }

108 }

109}

110

111void GlobalDCEPass::UpdateGVDependencies(GlobalValue &GV) {

112 SmallPtrSet<GlobalValue *, 8> Deps;

113 for (User *User : GV.users())

114 ComputeDependencies(User, Deps);

115 Deps.erase(&GV);

116 for (GlobalValue *GVU : Deps) {

117

118

119

120

121 if (VFESafeVTables.count(GVU) && isa(&GV)) {

122 LLVM_DEBUG(dbgs() << "Ignoring dep " << GVU->getName() << " -> "

123 << GV.getName() << "\n");

124 continue;

125 }

126 GVDependencies[GVU].insert(&GV);

127 }

128}

129

130

131void GlobalDCEPass::MarkLive(GlobalValue &GV,

133 auto const Ret = AliveGlobals.insert(&GV);

134 if (!Ret.second)

135 return;

136

137 if (Updates)

140 for (auto &&CM : make_range(ComdatMembers.equal_range(C))) {

141 MarkLive(*CM.second, Updates);

142

143 }

144 }

145}

146

147void GlobalDCEPass::ScanVTables(Module &M) {

149 LLVM_DEBUG(dbgs() << "Building type info -> vtable map\n");

150

151 for (GlobalVariable &GV : M.globals()) {

153 GV.getMetadata(LLVMContext::MD_type, Types);

155 continue;

156

157

158

159

160 for (MDNode *Type : Types) {

162

166 ->getZExtValue();

167

168 TypeIdMap[TypeID].insert(std::make_pair(&GV, Offset));

169 }

170

171

172

173

177 (InLTOPostLink &&

180 VFESafeVTables.insert(&GV);

181 }

182 }

183 }

184}

185

186void GlobalDCEPass::ScanVTableLoad(Function *Caller, Metadata *TypeId,

187 uint64_t CallOffset) {

188 for (const auto &VTableInfo : TypeIdMap[TypeId]) {

189 GlobalVariable *VTable = VTableInfo.first;

190 uint64_t VTableOffset = VTableInfo.second;

191

194 *Caller->getParent(), VTable);

195 if (!Ptr) {

196 LLVM_DEBUG(dbgs() << "can't find pointer in vtable!\n");

197 VFESafeVTables.erase(VTable);

198 continue;

199 }

200

202 if (!Callee) {

203 LLVM_DEBUG(dbgs() << "vtable entry is not function pointer!\n");

204 VFESafeVTables.erase(VTable);

205 continue;

206 }

207

209 << Callee->getName() << "\n");

210 GVDependencies[Caller].insert(Callee);

211 }

212}

213

214void GlobalDCEPass::ScanTypeCheckedLoadIntrinsics(Module &M) {

215 LLVM_DEBUG(dbgs() << "Scanning type.checked.load intrinsics\n");

216 Function *TypeCheckedLoadFunc =

219 &M, Intrinsic::type_checked_load_relative);

220

221 auto scan = [&](Function *CheckedLoadFunc) {

222 if (!CheckedLoadFunc)

223 return;

224

225 for (auto *U : CheckedLoadFunc->users()) {

227 if (!CI)

228 continue;

229

231 Value *TypeIdValue = CI->getArgOperand(2);

233

235 ScanVTableLoad(CI->getFunction(), TypeId, Offset->getZExtValue());

236 } else {

237

238

239 for (const auto &VTableInfo : TypeIdMap[TypeId]) {

240 VFESafeVTables.erase(VTableInfo.first);

241 }

242 }

243 }

244 };

245

246 scan(TypeCheckedLoadFunc);

247 scan(TypeCheckedLoadRelativeFunc);

248}

249

250void GlobalDCEPass::AddVirtualFunctionDependencies(Module &M) {

252 return;

253

254

255

256

257

259 M.getModuleFlag("Virtual Function Elim"));

260 if (!Val || Val->isZero())

261 return;

262

263 ScanVTables(M);

264

265 if (VFESafeVTables.empty())

266 return;

267

268 ScanTypeCheckedLoadIntrinsics(M);

269

271 dbgs() << "VFE safe vtables:\n";

272 for (auto *VTable : VFESafeVTables)

273 dbgs() << " " << VTable->getName() << "\n";

274 );

275}

276

279

280

281

282

283

284

285

286

287

288

291

292

294 if (Comdat *C = F.getComdat())

295 ComdatMembers.insert(std::make_pair(C, &F));

298 ComdatMembers.insert(std::make_pair(C, &GV));

300 if (Comdat *C = GA.getComdat())

301 ComdatMembers.insert(std::make_pair(C, &GA));

302

303

304

305 AddVirtualFunctionDependencies(M);

306

307

308 for (GlobalObject &GO : M.global_objects()) {

309 GO.removeDeadConstantUsers();

310

311

312

313 if (!GO.isDeclaration())

314 if (!GO.isDiscardableIfUnused())

315 MarkLive(GO);

316

317 UpdateGVDependencies(GO);

318 }

319

320

322 GA.removeDeadConstantUsers();

323

324 if (!GA.isDiscardableIfUnused())

325 MarkLive(GA);

326

327 UpdateGVDependencies(GA);

328 }

329

330

332 GIF.removeDeadConstantUsers();

333

334 if (!GIF.isDiscardableIfUnused())

335 MarkLive(GIF);

336

337 UpdateGVDependencies(GIF);

338 }

339

340

341

343 AliveGlobals.end()};

344 while (!NewLiveGVs.empty()) {

346 for (auto *GVD : GVDependencies[LGV])

347 MarkLive(*GVD, &NewLiveGVs);

348 }

349

350

351

352

353

354

355 std::vector<GlobalVariable *> DeadGlobalVars;

357 if (!AliveGlobals.count(&GV)) {

358 DeadGlobalVars.push_back(&GV);

359 if (GV.hasInitializer()) {

361 GV.setInitializer(nullptr);

363 Init->destroyConstant();

364 }

365 }

366

367

368 std::vector<Function *> DeadFunctions;

370 if (!AliveGlobals.count(&F)) {

371 DeadFunctions.push_back(&F);

372 if (F.isDeclaration())

373 F.deleteBody();

374 }

375

376

377 std::vector<GlobalAlias*> DeadAliases;

379 if (!AliveGlobals.count(&GA)) {

380 DeadAliases.push_back(&GA);

381 GA.setAliasee(nullptr);

382 }

383

384

385 std::vector<GlobalIFunc*> DeadIFuncs;

387 if (!AliveGlobals.count(&GIF)) {

388 DeadIFuncs.push_back(&GIF);

389 GIF.setResolver(nullptr);

390 }

391

392

393

394 auto EraseUnusedGlobalValue = [&](GlobalValue *GV) {

398 };

399

400 NumFunctions += DeadFunctions.size();

401 for (Function *F : DeadFunctions) {

402 if (F->use_empty()) {

403

404

405

406

407 ++NumVFuncs;

408

409

410

411

412

413

414

415

417

419 }

420 EraseUnusedGlobalValue(F);

421 }

422

423 NumVariables += DeadGlobalVars.size();

425 EraseUnusedGlobalValue(GV);

426

427 NumAliases += DeadAliases.size();

429 EraseUnusedGlobalValue(GA);

430

431 NumIFuncs += DeadIFuncs.size();

433 EraseUnusedGlobalValue(GIF);

434

435

436 AliveGlobals.clear();

437 ConstantDependenciesCache.clear();

438 GVDependencies.clear();

439 ComdatMembers.clear();

440 TypeIdMap.clear();

441 VFESafeVTables.clear();

442

446}

447

451 OS, MapClassName2PassName);

452 if (InLTOPostLink)

453 OS << "";

454}

static bool isEmptyFunction(Function *F)

Returns true if F is effectively empty.

Definition GlobalDCE.cpp:75

static cl::opt< bool > ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true), cl::desc("Enable virtual function elimination"))

Module.h This file contains the declarations for the Module class.

ModuleAnalysisManager MAM

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

This file defines the SmallPtrSet class.

This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...

#define STATISTIC(VARNAME, DESC)

LLVM Basic Block Representation.

static LLVM_ABI ConstantPointerNull * get(PointerType *T)

Static factory methods - Return objects of the specified value.

This is an important base class in LLVM.

const Constant * stripPointerCasts() const

LLVM_ABI void removeDeadConstantUsers() const

If there are any dead constant users dangling off of this constant, remove them.

Pass to remove unused function declarations.

LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)

Definition GlobalDCE.cpp:448

LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)

Definition GlobalDCE.cpp:277

@ VCallVisibilityLinkageUnit

@ VCallVisibilityTranslationUnit

LLVM_ABI bool isDeclaration() const

Return true if the primary definition of this global value is outside of the current translation unit...

LLVM_ABI const Comdat * getComdat() const

LLVM_ABI void eraseFromParent()

This method unlinks 'this' from the containing module and deletes it.

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

A Module instance is used to store all the information related to an LLVM module.

static LLVM_ABI PassRegistry * getPassRegistry()

getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses none()

Convenience factory function for the empty preserved set.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...

bool erase(PtrType Ptr)

Remove pointer from the set.

void insert_range(Range &&R)

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

LLVM Value Representation.

iterator_range< user_iterator > users()

LLVM_ABI StringRef getName() const

Return a constant reference to the value's name.

MDNode * getMetadata(unsigned KindID) const

Get the current metadata attachments for the given kind, if any.

An efficient, type-erasing, non-owning reference to a callable.

This class implements an extremely fast bulk output stream that can only output to a stream.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ C

The default llvm calling convention, compatible with C.

LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)

Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.

@ CE

Windows NT (Windows on ARM)

initializer< Ty > init(const Ty &Val)

std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)

Extract a Value from Metadata, if any, allowing null.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

iterator_range< T > make_range(T x, T y)

Convenience function for iterating over sub-ranges.

LLVM_ABI ModulePass * createGlobalDCEPass()

bool isSafeToDestroyConstant(const Constant *C)

It is safe to destroy a constant iff it is only used by constants itself.

LLVM_ABI void initializeGlobalDCELegacyPassPass(PassRegistry &)

bool optimizeGlobalCtorsList(Module &M, function_ref< bool(uint32_t, Function *)> ShouldRemove)

Call "ShouldRemove" for every entry in M's global_ctor list and remove the entries for which it retur...

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

void replaceRelativePointerUsersWithZero(Constant *C)

Finds the same "relative pointer" pattern as described above, where the target is C,...

AnalysisManager< Module > ModuleAnalysisManager

Convenience typedef for the Module analysis manager.

Constant * getPointerAtOffset(Constant *I, uint64_t Offset, Module &M, Constant *TopLevelGlobal=nullptr)

Processes a Constant recursively looking into elements of arrays, structs and expressions to find a t...

A CRTP mix-in to automatically provide informational APIs needed for passes.