Skip to content

Commit 89da790

Browse files
committed
Implement in TargetLibraryInfo info about escaping arguments and return value in standard library calls
1 parent f0ca7c2 commit 89da790

9 files changed

Lines changed: 762 additions & 244 deletions

File tree

llvm/include/llvm/Analysis/EscapeAnalysis.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class EscapeAnalysisInfo {
105105
/// escaping by calls)
106106
explicit EscapeAnalysisInfo(
107107
const Function &Fn,
108+
const TargetLibraryInfo &TLI_,
108109
std::shared_ptr<NonEscapingFuncsMap> NonEscapingFuncs_ = nullptr,
109110
std::shared_ptr<IPABottomTopMap> IPAFuncEscInfo = nullptr,
110111
std::shared_ptr<IPAArgEscFromCallsMap> IPAArgEscFromCallers_ = nullptr);
@@ -114,7 +115,8 @@ class EscapeAnalysisInfo {
114115
/// Recursively search in the instruction for the underlying objects which
115116
/// may escape
116117
static SmallVector<UnderlObjTy> getUnderlyingMayEscObjs(
117-
const Value *V, unsigned MaxLookup = MaxUnderlObjLookup,
118+
const Value *V, const TargetLibraryInfo &TLI,
119+
unsigned MaxLookup = MaxUnderlObjLookup,
118120
std::shared_ptr<IPABottomTopMap> IPAFuncEscInfo = nullptr);
119121

120122
/// Is Value V is escaping somewhere in the function
@@ -168,6 +170,8 @@ class EscapeAnalysisInfo {
168170
/// List of functions whose arguments don't escape
169171
std::shared_ptr<NonEscapingFuncsMap> NonEscapingFuncs;
170172

173+
const TargetLibraryInfo &TLI;
174+
171175
class PointsToRelTy {
172176
using PointeeListTy = SmallSet<ObjAndPath, 4>;
173177
using PathToPointeeMap = std::map<FieldPathTy, PointeeListTy>;
@@ -287,13 +291,13 @@ class EscapeAnalysisInfo {
287291

288292
/// Functions to process operand/instruction pair to get escape status
289293
EscInfoTy getEscInfoCall(const Use &U, const Instruction *I) const;
290-
static EscInfoTy getEscInfoLoad(const Instruction *I);
291-
static EscInfoTy getEscInfoStore(const Use &U, const Instruction *I);
292-
static EscInfoTy getEscInfoAtomicRMW(const Use &U, const Instruction *I);
293-
static EscInfoTy getEscInfoAtomicCmpXchg(const Use &U, const Instruction *I);
294-
static EscInfoTy getEscInfoGetElementPtr(const Instruction *I);
295-
static EscInfoTy getEscInfoICmp(const Use &U, const Instruction *I);
296-
static EscInfoTy getEscInfoRet(const Use &U);
294+
EscInfoTy getEscInfoLoad(const Instruction *I) const;
295+
EscInfoTy getEscInfoStore(const Use &U, const Instruction *I) const;
296+
EscInfoTy getEscInfoAtomicRMW(const Use &U, const Instruction *I) const;
297+
EscInfoTy getEscInfoAtomicCmpXchg(const Use &U, const Instruction *I) const;
298+
EscInfoTy getEscInfoGetElementPtr(const Instruction *I) const;
299+
EscInfoTy getEscInfoICmp(const Use &U, const Instruction *I) const;
300+
EscInfoTy getEscInfoRet(const Use &U) const;
297301

298302
/// Print escaped objects in some path from Entry to BB
299303
void printEscapingForBB(const BasicBlock *BB, raw_ostream &OS) const;
@@ -315,6 +319,7 @@ class EscapeAnalysisInfo {
315319
class EscapeAnalysisGlobalInfo {
316320
Module &M;
317321
DenseMap<const Function *, EscapeAnalysisInfo> FuncEscapeInfo;
322+
ModuleAnalysisManager &MAM;
318323

319324
/// List of functions whose arguments don't escape
320325
static constexpr auto FuncWhiteListFileName = "ea_summary.txt";
@@ -386,11 +391,14 @@ class EscapeAnalysisGlobalInfo {
386391
void writeIPASummary();
387392

388393
public:
389-
explicit EscapeAnalysisGlobalInfo(CallGraph &CG, Module &M);
394+
explicit EscapeAnalysisGlobalInfo(CallGraph &CG, Module &M,
395+
ModuleAnalysisManager &MAM_);
390396
void print(Module &M, raw_ostream &O) const;
391397

392398
/// For given pointer, get underlying objects, and get escape status for them
393-
bool isEscapedUndrlObjOrPointee(const Value *Addr, const BasicBlock *BB,
399+
bool isEscapedUndrlObjOrPointee(const Value *Addr,
400+
const TargetLibraryInfo &TLI,
401+
const BasicBlock *BB,
394402
EscapeAnalysisInfo::EscReasonTy &EscReason);
395403

396404
/// Is Value V is escaping in some path from Entry to BB in the function F
@@ -412,7 +420,7 @@ class EscapeAnalysis : public AnalysisInfoMixin<EscapeAnalysis> {
412420

413421
public:
414422
using Result = EscapeAnalysisInfo;
415-
static Result run(const Function &F, FunctionAnalysisManager &AM);
423+
static Result run(Function &F, FunctionAnalysisManager &AM);
416424
};
417425

418426
/// Printer pass for the \c EscapeAnalysis results.

llvm/include/llvm/Analysis/TargetLibraryInfo.h

Lines changed: 3 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -442,153 +442,13 @@ class TargetLibraryInfo {
442442
return false;
443443
}
444444

445+
static bool doesArgEscape(LibFunc F, unsigned ArgNo);
446+
static bool isReturnValueEscaping(LibFunc F);
445447

446448
static bool isLockAcquireFunction(const Function &F);
447449
static bool isLockReleaseFunction(const Function &F);
448450

449-
bool isSyncFree(LibFunc F) const {
450-
if (getState(F) == TargetLibraryInfoImpl::Unavailable)
451-
return false; // If the function is unavailable, it cannot be sync-free
452-
453-
switch (F) {
454-
// Functions that are NOT sync-free (they use synchronization)
455-
456-
// Direct atomic operations and guard mechanisms:
457-
case LibFunc_atomic_load: case LibFunc_atomic_store:
458-
case LibFunc_cxa_guard_abort: case LibFunc_cxa_guard_acquire:
459-
case LibFunc_cxa_guard_release:
460-
461-
// Explicit file locks:
462-
case LibFunc_flockfile: case LibFunc_ftrylockfile: case LibFunc_funlockfile:
463-
464-
// Standard I/O (versions without _unlocked suffix imply internal locks):
465-
// Operations with FILE* or global stdin/stdout/stderr
466-
case LibFunc_fclose: case LibFunc_fdopen: case LibFunc_fflush:
467-
case LibFunc_fgetc: case LibFunc_fgetpos: case LibFunc_fgets:
468-
case LibFunc_fopen: case LibFunc_fopen64: case LibFunc_fprintf:
469-
case LibFunc_fiprintf: // Assumed to be an analog of fprintf for integers to FILE*
470-
case LibFunc_small_fprintf: case LibFunc_fputc: case LibFunc_fputs:
471-
case LibFunc_fread: case LibFunc_fscanf: case LibFunc_fseek:
472-
case LibFunc_fseeko: case LibFunc_fseeko64: case LibFunc_fsetpos:
473-
case LibFunc_ftell: case LibFunc_ftello: case LibFunc_ftello64:
474-
case LibFunc_fwrite: case LibFunc_getc: case LibFunc_getchar:
475-
case LibFunc_gets: // Uses stdio, usually with locking
476-
case LibFunc_perror: // Writes to stderr, which is usually locked
477-
case LibFunc_printf:
478-
case LibFunc_iprintf: // Printing integers, usually to stdout
479-
case LibFunc_small_printf: case LibFunc_putc: case LibFunc_putchar:
480-
case LibFunc_puts: case LibFunc_rewind: case LibFunc_scanf:
481-
case LibFunc_dunder_isoc99_scanf: // This is scanf
482-
case LibFunc_setbuf: // Modifies FILE stream buffering, implies synchronization
483-
case LibFunc_setvbuf: // Modifies FILE stream buffering, implies synchronization
484-
case LibFunc_tmpfile: case LibFunc_tmpfile64: case LibFunc_ungetc:
485-
case LibFunc_vfprintf: case LibFunc_vfscanf: case LibFunc_vprintf:
486-
case LibFunc_vscanf:
487-
case LibFunc_under_IO_getc: // Assumed to be similar to fgetc
488-
case LibFunc_under_IO_putc: // Assumed to be similar to fputc
489-
case LibFunc_clearerr: // Modifies FILE state, likely requires synchronization
490-
case LibFunc_feof: // Reads FILE state, likely requires synchronization
491-
case LibFunc_ferror: // Reads FILE state, likely requires synchronization
492-
case LibFunc_fileno: // Reads FILE state, conservatively assumed to potentially require synchronization
493-
494-
// Memory allocation/deallocation (usually internally synchronized):
495-
// MSVC new/delete operators
496-
case LibFunc_msvc_new_int:
497-
case LibFunc_msvc_new_int_nothrow:
498-
case LibFunc_msvc_new_longlong:
499-
case LibFunc_msvc_new_longlong_nothrow:
500-
case LibFunc_msvc_delete_ptr32:
501-
case LibFunc_msvc_delete_ptr32_nothrow:
502-
case LibFunc_msvc_delete_ptr32_int:
503-
case LibFunc_msvc_delete_ptr64:
504-
case LibFunc_msvc_delete_ptr64_nothrow:
505-
case LibFunc_msvc_delete_ptr64_longlong:
506-
case LibFunc_msvc_new_array_int:
507-
case LibFunc_msvc_new_array_int_nothrow:
508-
case LibFunc_msvc_new_array_longlong:
509-
case LibFunc_msvc_new_array_longlong_nothrow:
510-
case LibFunc_msvc_delete_array_ptr32:
511-
case LibFunc_msvc_delete_array_ptr32_nothrow:
512-
case LibFunc_msvc_delete_array_ptr32_int:
513-
case LibFunc_msvc_delete_array_ptr64:
514-
case LibFunc_msvc_delete_array_ptr64_nothrow:
515-
case LibFunc_msvc_delete_array_ptr64_longlong:
516-
// Itanium C++ ABI new/delete operators
517-
case LibFunc_ZdaPv: case LibFunc_ZdaPvRKSt9nothrow_t:
518-
case LibFunc_ZdaPvSt11align_val_t:
519-
case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t:
520-
case LibFunc_ZdaPvj: case LibFunc_ZdaPvjSt11align_val_t:
521-
case LibFunc_ZdaPvm: case LibFunc_ZdaPvmSt11align_val_t:
522-
case LibFunc_ZdlPv: case LibFunc_ZdlPvRKSt9nothrow_t:
523-
case LibFunc_ZdlPvSt11align_val_t:
524-
case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t:
525-
case LibFunc_ZdlPvj: case LibFunc_ZdlPvjSt11align_val_t:
526-
case LibFunc_ZdlPvm: case LibFunc_ZdlPvmSt11align_val_t:
527-
case LibFunc_Znaj: case LibFunc_ZnajRKSt9nothrow_t:
528-
case LibFunc_ZnajSt11align_val_t:
529-
case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t:
530-
case LibFunc_Znam: case LibFunc_Znam12__hot_cold_t:
531-
case LibFunc_ZnamRKSt9nothrow_t:
532-
case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
533-
case LibFunc_ZnamSt11align_val_t:
534-
case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
535-
case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
536-
case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
537-
case LibFunc_Znwj: case LibFunc_ZnwjRKSt9nothrow_t:
538-
case LibFunc_ZnwjSt11align_val_t:
539-
case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t:
540-
case LibFunc_Znwm: case LibFunc_Znwm12__hot_cold_t:
541-
case LibFunc_ZnwmRKSt9nothrow_t:
542-
case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
543-
case LibFunc_ZnwmSt11align_val_t:
544-
case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
545-
case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
546-
case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
547-
// Standard C allocators
548-
case LibFunc_aligned_alloc: case LibFunc_calloc: case LibFunc_free:
549-
case LibFunc_malloc:
550-
case LibFunc_memalign: // Obsolete, but if present, it's an allocator
551-
case LibFunc_posix_memalign: case LibFunc_realloc:
552-
case LibFunc_reallocf: // Calls realloc, then free on failure
553-
case LibFunc_valloc: // Obsolete, but if present, it's an allocator
554-
case LibFunc_strdup: // Calls malloc
555-
case LibFunc_dunder_strdup: // Calls malloc
556-
case LibFunc_strndup: // Calls malloc
557-
case LibFunc_dunder_strndup: // Calls malloc
558-
// OpenMP runtime allocators
559-
case LibFunc___kmpc_alloc_shared: case LibFunc___kmpc_free_shared:
560-
// Vector allocators (assuming they might be synchronized like standard ones)
561-
case LibFunc_vec_calloc: case LibFunc_vec_free: case LibFunc_vec_malloc:
562-
case LibFunc_vec_realloc:
563-
564-
// Process/system level utilities that are inherently synchronizing
565-
// or involve significant system state changes:
566-
case LibFunc_fork:
567-
case LibFunc_pclose: // Waits for process completion
568-
case LibFunc_popen: // Creates a pipe and process
569-
case LibFunc_system: // Creates a shell, involves fork/exec
570-
case LibFunc_execl: case LibFunc_execle: case LibFunc_execlp:
571-
case LibFunc_execv: case LibFunc_execvP: case LibFunc_execve:
572-
case LibFunc_execvp: case LibFunc_execvpe:
573-
574-
// Other potentially synchronized standard library functions:
575-
case LibFunc_atexit: // Modification of a global list
576-
case LibFunc_cxa_atexit: // Modification of a global list
577-
case LibFunc_getenv: // Access to shared environment, may be locked
578-
case LibFunc_mktime: // Access to global/static timezone data
579-
case LibFunc_ctermid: // Often uses a static buffer, potentially requires synchronization
580-
case LibFunc_getlogin_r: // System call to get information
581-
case LibFunc_getpwnam: // Access to system database (e.g., /etc/passwd)
582-
583-
return false; // These functions are NOT sync-free.
584-
585-
default:
586-
// All other functions (mathematical, string operations without memory allocation,
587-
// I/O with _unlocked suffix, buffer operations like sprintf/sscanf, etc.)
588-
// are considered sync-free.
589-
return true;
590-
}
591-
}
451+
bool isSyncFree(LibFunc F) const;
592452

593453
StringRef getName(LibFunc F) const {
594454
auto State = getState(F);

0 commit comments

Comments
 (0)