1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
|
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//===- SimplifyLibCalls.h - Library call simplifier -------------*- 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 exposes an interface to build some C language libcalls for
// optimization passes that need to call the various functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_UTILS_SIMPLIFYLIBCALLS_H
#define LLVM_TRANSFORMS_UTILS_SIMPLIFYLIBCALLS_H
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
namespace llvm {
class StringRef;
class Value;
class CallInst;
class DataLayout;
class Instruction;
class IRBuilderBase;
class Function;
class OptimizationRemarkEmitter;
class BlockFrequencyInfo;
class ProfileSummaryInfo;
/// This class implements simplifications for calls to fortified library
/// functions (__st*cpy_chk, __memcpy_chk, __memmove_chk, __memset_chk), to,
/// when possible, replace them with their non-checking counterparts.
/// Other optimizations can also be done, but it's possible to disable them and
/// only simplify needless use of the checking versions (when the object size
/// is unknown) by passing true for OnlyLowerUnknownSize.
class FortifiedLibCallSimplifier {
private:
const TargetLibraryInfo *TLI;
bool OnlyLowerUnknownSize;
public:
FortifiedLibCallSimplifier(const TargetLibraryInfo *TLI,
bool OnlyLowerUnknownSize = false);
/// Take the given call instruction and return a more
/// optimal value to replace the instruction with or 0 if a more
/// optimal form can't be found.
/// The call must not be an indirect call.
Value *optimizeCall(CallInst *CI, IRBuilderBase &B);
private:
Value *optimizeMemCpyChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemMoveChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemSetChk(CallInst *CI, IRBuilderBase &B);
/// Str/Stp cpy are similar enough to be handled in the same functions.
Value *optimizeStrpCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func);
Value *optimizeStrpNCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func);
Value *optimizeStrLenChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemPCpyChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemCCpyChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeSNPrintfChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeSPrintfChk(CallInst *CI,IRBuilderBase &B);
Value *optimizeStrCatChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrLCat(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNCatChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrLCpyChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeVSNPrintfChk(CallInst *CI, IRBuilderBase &B);
Value *optimizeVSPrintfChk(CallInst *CI, IRBuilderBase &B);
/// Checks whether the call \p CI to a fortified libcall is foldable
/// to the non-fortified version.
///
/// \param CI the call to the fortified libcall.
///
/// \param ObjSizeOp the index of the object size parameter of this chk
/// function. Not optional since this is mandatory.
///
/// \param SizeOp optionally set to the parameter index of an explicit buffer
/// size argument. For instance, set to '2' for __strncpy_chk.
///
/// \param StrOp optionally set to the parameter index of the source string
/// parameter to strcpy-like functions, where only the strlen of the source
/// will be writtin into the destination.
///
/// \param FlagsOp optionally set to the parameter index of a 'flags'
/// parameter. These are used by an implementation to opt-into stricter
/// checking.
bool isFortifiedCallFoldable(CallInst *CI, unsigned ObjSizeOp,
std::optional<unsigned> SizeOp = std::nullopt,
std::optional<unsigned> StrOp = std::nullopt,
std::optional<unsigned> FlagsOp = std::nullopt);
};
/// LibCallSimplifier - This class implements a collection of optimizations
/// that replace well formed calls to library functions with a more optimal
/// form. For example, replacing 'printf("Hello!")' with 'puts("Hello!")'.
class LibCallSimplifier {
private:
FortifiedLibCallSimplifier FortifiedSimplifier;
const DataLayout &DL;
const TargetLibraryInfo *TLI;
OptimizationRemarkEmitter &ORE;
BlockFrequencyInfo *BFI;
ProfileSummaryInfo *PSI;
bool UnsafeFPShrink = false;
function_ref<void(Instruction *, Value *)> Replacer;
function_ref<void(Instruction *)> Eraser;
/// Internal wrapper for RAUW that is the default implementation.
///
/// Other users may provide an alternate function with this signature instead
/// of this one.
static void replaceAllUsesWithDefault(Instruction *I, Value *With) {
I->replaceAllUsesWith(With);
}
/// Internal wrapper for eraseFromParent that is the default implementation.
static void eraseFromParentDefault(Instruction *I) { I->eraseFromParent(); }
/// Replace an instruction's uses with a value using our replacer.
void replaceAllUsesWith(Instruction *I, Value *With);
/// Erase an instruction from its parent with our eraser.
void eraseFromParent(Instruction *I);
/// Replace an instruction with a value and erase it from its parent.
void substituteInParent(Instruction *I, Value *With) {
replaceAllUsesWith(I, With);
eraseFromParent(I);
}
public:
LibCallSimplifier(
const DataLayout &DL, const TargetLibraryInfo *TLI,
OptimizationRemarkEmitter &ORE,
BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI,
function_ref<void(Instruction *, Value *)> Replacer =
&replaceAllUsesWithDefault,
function_ref<void(Instruction *)> Eraser = &eraseFromParentDefault);
/// optimizeCall - Take the given call instruction and return a more
/// optimal value to replace the instruction with or 0 if a more
/// optimal form can't be found. Note that the returned value may
/// be equal to the instruction being optimized. In this case all
/// other instructions that use the given instruction were modified
/// and the given instruction is dead.
/// The call must not be an indirect call.
Value *optimizeCall(CallInst *CI, IRBuilderBase &B);
private:
// String and Memory Library Call Optimizations
Value *optimizeStrCat(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNCat(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrChr(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrRChr(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrCmp(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNCmp(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNDup(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeStpCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrLCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrLen(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrNLen(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrPBrk(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrTo(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrSpn(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrCSpn(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrStr(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemChr(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemRChr(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemCmp(CallInst *CI, IRBuilderBase &B);
Value *optimizeBCmp(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemCmpBCmpCommon(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemCCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemPCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemCpy(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemMove(CallInst *CI, IRBuilderBase &B);
Value *optimizeMemSet(CallInst *CI, IRBuilderBase &B);
Value *optimizeRealloc(CallInst *CI, IRBuilderBase &B);
Value *optimizeWcslen(CallInst *CI, IRBuilderBase &B);
Value *optimizeBCopy(CallInst *CI, IRBuilderBase &B);
// Helper to optimize stpncpy and strncpy.
Value *optimizeStringNCpy(CallInst *CI, bool RetEnd, IRBuilderBase &B);
// Wrapper for all String/Memory Library Call Optimizations
Value *optimizeStringMemoryLibCall(CallInst *CI, IRBuilderBase &B);
// Math Library Optimizations
Value *optimizeCAbs(CallInst *CI, IRBuilderBase &B);
Value *optimizePow(CallInst *CI, IRBuilderBase &B);
Value *replacePowWithExp(CallInst *Pow, IRBuilderBase &B);
Value *replacePowWithSqrt(CallInst *Pow, IRBuilderBase &B);
Value *optimizeExp2(CallInst *CI, IRBuilderBase &B);
Value *optimizeFMinFMax(CallInst *CI, IRBuilderBase &B);
Value *optimizeLog(CallInst *CI, IRBuilderBase &B);
Value *optimizeSqrt(CallInst *CI, IRBuilderBase &B);
Value *optimizeSinCosPi(CallInst *CI, IRBuilderBase &B);
Value *optimizeTan(CallInst *CI, IRBuilderBase &B);
// Wrapper for all floating point library call optimizations
Value *optimizeFloatingPointLibCall(CallInst *CI, LibFunc Func,
IRBuilderBase &B);
// Integer Library Call Optimizations
Value *optimizeFFS(CallInst *CI, IRBuilderBase &B);
Value *optimizeFls(CallInst *CI, IRBuilderBase &B);
Value *optimizeAbs(CallInst *CI, IRBuilderBase &B);
Value *optimizeIsDigit(CallInst *CI, IRBuilderBase &B);
Value *optimizeIsAscii(CallInst *CI, IRBuilderBase &B);
Value *optimizeToAscii(CallInst *CI, IRBuilderBase &B);
Value *optimizeAtoi(CallInst *CI, IRBuilderBase &B);
Value *optimizeStrToInt(CallInst *CI, IRBuilderBase &B, bool AsSigned);
// Formatting and IO Library Call Optimizations
Value *optimizeErrorReporting(CallInst *CI, IRBuilderBase &B,
int StreamArg = -1);
Value *optimizePrintF(CallInst *CI, IRBuilderBase &B);
Value *optimizeSPrintF(CallInst *CI, IRBuilderBase &B);
Value *optimizeSnPrintF(CallInst *CI, IRBuilderBase &B);
Value *optimizeFPrintF(CallInst *CI, IRBuilderBase &B);
Value *optimizeFWrite(CallInst *CI, IRBuilderBase &B);
Value *optimizeFPuts(CallInst *CI, IRBuilderBase &B);
Value *optimizePuts(CallInst *CI, IRBuilderBase &B);
// Helper methods
Value* emitSnPrintfMemCpy(CallInst *CI, Value *StrArg, StringRef Str,
uint64_t N, IRBuilderBase &B);
Value *emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len,
IRBuilderBase &B);
void classifyArgUse(Value *Val, Function *F, bool IsFloat,
SmallVectorImpl<CallInst *> &SinCalls,
SmallVectorImpl<CallInst *> &CosCalls,
SmallVectorImpl<CallInst *> &SinCosCalls);
Value *optimizePrintFString(CallInst *CI, IRBuilderBase &B);
Value *optimizeSPrintFString(CallInst *CI, IRBuilderBase &B);
Value *optimizeSnPrintFString(CallInst *CI, IRBuilderBase &B);
Value *optimizeFPrintFString(CallInst *CI, IRBuilderBase &B);
/// hasFloatVersion - Checks if there is a float version of the specified
/// function by checking for an existing function with name FuncName + f
bool hasFloatVersion(const Module *M, StringRef FuncName);
/// Shared code to optimize strlen+wcslen and strnlen+wcsnlen.
Value *optimizeStringLength(CallInst *CI, IRBuilderBase &B, unsigned CharSize,
Value *Bound = nullptr);
};
} // End llvm namespace
#endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
|