LLVM 22.0.0git
FatLTOCleanup.cpp
Go to the documentation of this file.
1//===- FatLtoCleanup.cpp - clean up IR for the FatLTO pipeline --*- C++ -*-===//
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 file defines operations used to clean up IR for the FatLTO pipeline.
10// Instrumentation that is beneficial for bitcode sections used in LTO may
11// need to be cleaned up to finish non-LTO compilation. llvm.checked.load is
12// an example of an instruction that we want to preserve for LTO, but is
13// incorrect to leave unchanged during the per-TU compilation in FatLTO.
14//
15//===----------------------------------------------------------------------===//
16
18#include "llvm/IR/Function.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/Intrinsics.h"
21#include "llvm/IR/Module.h"
22#include "llvm/IR/PassManager.h"
23#include "llvm/IR/Use.h"
24#include "llvm/Support/Debug.h"
25
26using namespace llvm;
27
28#define DEBUG_TYPE "fatlto-cleanup"
29
30namespace {
31// Replaces uses of llvm.type.checked.load instructions with unchecked loads.
32// In essence, we're undoing the frontends instrumentation, since it isn't
33// correct for the non-LTO part of a FatLTO object.
34//
35// llvm.type.checked.load instruction sequences always have a particular form:
36//
37// clang-format off
38//
39// %0 = tail call { ptr, i1 } @llvm.type.checked.load(ptr %vtable, i32 0, metadata !"foo"), !nosanitize !0
40// %1 = extractvalue { ptr, i1 } %0, 1, !nosanitize !0
41// br i1 %1, label %cont2, label %trap1, !nosanitize !0
42//
43// trap1: ; preds = %entry
44// tail call void @llvm.ubsantrap(i8 2) #3, !nosanitize !0
45// unreachable, !nosanitize !0
46//
47// cont2: ; preds = %entry
48// %2 = extractvalue { ptr, i1 } %0, 0, !nosanitize !0
49// %call = tail call noundef i64 %2(ptr noundef nonnull align 8 dereferenceable(8) %p1) #4
50//
51// clang-format on
52//
53// In this sequence, the vtable pointer is first loaded and checked against some
54// metadata. The result indicates failure, then the program traps. On the
55// success path, the pointer is used to make an indirect call to the function
56// pointer loaded from the vtable.
57//
58// Since we won't be able to lower this correctly later in non-LTO builds, we
59// need to drop the special load and trap, and emit a normal load of the
60// function pointer from the vtable.
61//
62// This is straight forward, since the checked load can be replaced w/ a load
63// of the vtable pointer and a GEP instruction to index into the vtable and get
64// the correct method/function pointer. We replace the "check" with a constant
65// indicating success, which allows later passes to simplify control flow and
66// remove any now dead instructions.
67//
68// This logic holds for both llvm.type.checked.load and
69// llvm.type.checked.load.relative instructions.
70static bool cleanUpTypeCheckedLoad(Module &M, Function &CheckedLoadFn,
71 bool IsRelative) {
72 bool Changed = false;
73 for (User *User : llvm::make_early_inc_range(CheckedLoadFn.users())) {
75 if (!I)
76 continue;
77 IRBuilder<> IRB(I);
78 Value *Ptr = I->getOperand(0);
79 Value *Offset = I->getOperand(1);
80 Type *PtrTy = I->getType()->getStructElementType(0);
81 ConstantInt *True = ConstantInt::getTrue(M.getContext());
82 Instruction *Load;
83 if (IsRelative) {
84 Load =
85 IRB.CreateIntrinsic(Intrinsic::load_relative, {Offset->getType()},
86 {Ptr, Offset}, /*FMFSource=*/nullptr, "rel_load");
87 } else {
88 Value *PtrAdd = IRB.CreatePtrAdd(Ptr, Offset);
89 Load = IRB.CreateLoad(PtrTy, PtrAdd, "vfunc");
90 }
91
92 Value *Replacement = PoisonValue::get(I->getType());
93 Replacement = IRB.CreateInsertValue(Replacement, True, {1});
94 Replacement = IRB.CreateInsertValue(Replacement, Load, {0});
95 I->replaceAllUsesWith(Replacement);
96
97 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": erase " << *I << "\n");
98 I->eraseFromParent();
99 Changed = true;
100 }
101 if (Changed)
102 CheckedLoadFn.eraseFromParent();
103 return Changed;
104}
105} // namespace
106
108 Function *TypeCheckedLoadFn =
109 Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_checked_load);
110 Function *TypeCheckedLoadRelFn = Intrinsic::getDeclarationIfExists(
111 &M, Intrinsic::type_checked_load_relative);
112
113 bool Changed = false;
114 if (TypeCheckedLoadFn)
115 Changed |= cleanUpTypeCheckedLoad(M, *TypeCheckedLoadFn, false);
116 if (TypeCheckedLoadRelFn)
117 Changed |= cleanUpTypeCheckedLoad(M, *TypeCheckedLoadRelFn, true);
118
119 if (Changed)
121 return PreservedAnalyses::all();
122}
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This defines the Use class.
#define I(x, y, z)
Definition MD5.cpp:58
#define LLVM_DEBUG(...)
Definition Debug.h:114
This is the shared class of boolean and integer constants.
Definition Constants.h:87
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Function.cpp:448
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2625
Value * CreatePtrAdd(Value *Ptr, Value *Offset, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
Definition IRBuilder.h:2036
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition IRBuilder.h:1847
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2780
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
LLVM Value Representation.
Definition Value.h:75
iterator_range< user_iterator > users()
Definition Value.h:426
Changed
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.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:649
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:626
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39