Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/FatLTOCleanup.cpp
213799 views
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
17
#include "llvm/Transforms/IPO/FatLTOCleanup.h"
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
26
using namespace llvm;
27
28
#define DEBUG_TYPE "fatlto-cleanup"
29
30
namespace {
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.
70
static bool cleanUpTypeCheckedLoad(Module &M, Function &CheckedLoadFn,
71
bool IsRelative) {
72
bool Changed = false;
73
for (User *User : llvm::make_early_inc_range(CheckedLoadFn.users())) {
74
Instruction *I = dyn_cast<Instruction>(User);
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
107
PreservedAnalyses FatLtoCleanup::run(Module &M, ModuleAnalysisManager &AM) {
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)
120
return PreservedAnalyses::none();
121
return PreservedAnalyses::all();
122
}
123
124