diff options
Diffstat (limited to 'llvm/lib/Transforms/Utils/BuildLibCalls.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 1396 |
1 files changed, 1396 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp new file mode 100644 index 0000000000000..71316ce8f7583 --- /dev/null +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -0,0 +1,1396 @@ +//===- BuildLibCalls.cpp - Utility builder for libcalls -------------------===// +// +// 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 implements some functions that will create standard C libcalls. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/BuildLibCalls.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Analysis/MemoryBuiltins.h" + +using namespace llvm; + +#define DEBUG_TYPE "build-libcalls" + +//- Infer Attributes ---------------------------------------------------------// + +STATISTIC(NumReadNone, "Number of functions inferred as readnone"); +STATISTIC(NumReadOnly, "Number of functions inferred as readonly"); +STATISTIC(NumArgMemOnly, "Number of functions inferred as argmemonly"); +STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind"); +STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); +STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly"); +STATISTIC(NumNoAlias, "Number of function returns inferred as noalias"); +STATISTIC(NumNonNull, "Number of function returns inferred as nonnull returns"); +STATISTIC(NumReturnedArg, "Number of arguments inferred as returned"); + +static bool setDoesNotAccessMemory(Function &F) { + if (F.doesNotAccessMemory()) + return false; + F.setDoesNotAccessMemory(); + ++NumReadNone; + return true; +} + +static bool setOnlyReadsMemory(Function &F) { + if (F.onlyReadsMemory()) + return false; + F.setOnlyReadsMemory(); + ++NumReadOnly; + return true; +} + +static bool setOnlyAccessesArgMemory(Function &F) { + if (F.onlyAccessesArgMemory()) + return false; + F.setOnlyAccessesArgMemory(); + ++NumArgMemOnly; + return true; +} + +static bool setDoesNotThrow(Function &F) { + if (F.doesNotThrow()) + return false; + F.setDoesNotThrow(); + ++NumNoUnwind; + return true; +} + +static bool setRetDoesNotAlias(Function &F) { + if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias)) + return false; + F.addAttribute(AttributeList::ReturnIndex, Attribute::NoAlias); + ++NumNoAlias; + return true; +} + +static bool setDoesNotCapture(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::NoCapture)) + return false; + F.addParamAttr(ArgNo, Attribute::NoCapture); + ++NumNoCapture; + return true; +} + +static bool setDoesNotAlias(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::NoAlias)) + return false; + F.addParamAttr(ArgNo, Attribute::NoAlias); + ++NumNoAlias; + return true; +} + +static bool setOnlyReadsMemory(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::ReadOnly)) + return false; + F.addParamAttr(ArgNo, Attribute::ReadOnly); + ++NumReadOnlyArg; + return true; +} + +static bool setRetNonNull(Function &F) { + assert(F.getReturnType()->isPointerTy() && + "nonnull applies only to pointers"); + if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NonNull)) + return false; + F.addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); + ++NumNonNull; + return true; +} + +static bool setReturnedArg(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::Returned)) + return false; + F.addParamAttr(ArgNo, Attribute::Returned); + ++NumReturnedArg; + return true; +} + +static bool setNonLazyBind(Function &F) { + if (F.hasFnAttribute(Attribute::NonLazyBind)) + return false; + F.addFnAttr(Attribute::NonLazyBind); + return true; +} + +static bool setDoesNotFreeMemory(Function &F) { + if (F.hasFnAttribute(Attribute::NoFree)) + return false; + F.addFnAttr(Attribute::NoFree); + return true; +} + +bool llvm::inferLibFuncAttributes(Module *M, StringRef Name, + const TargetLibraryInfo &TLI) { + Function *F = M->getFunction(Name); + if (!F) + return false; + return inferLibFuncAttributes(*F, TLI); +} + +bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { + LibFunc TheLibFunc; + if (!(TLI.getLibFunc(F, TheLibFunc) && TLI.has(TheLibFunc))) + return false; + + bool Changed = false; + + if(!isLibFreeFunction(&F, TheLibFunc) && !isReallocLikeFn(&F, &TLI)) + Changed |= setDoesNotFreeMemory(F); + + if (F.getParent() != nullptr && F.getParent()->getRtLibUseGOT()) + Changed |= setNonLazyBind(F); + + switch (TheLibFunc) { + case LibFunc_strlen: + case LibFunc_wcslen: + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_strchr: + case LibFunc_strrchr: + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + return Changed; + case LibFunc_strtol: + case LibFunc_strtod: + case LibFunc_strtof: + case LibFunc_strtoul: + case LibFunc_strtoll: + case LibFunc_strtold: + case LibFunc_strtoull: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_strcpy: + case LibFunc_strncpy: + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotAlias(F, 1); + LLVM_FALLTHROUGH; + case LibFunc_strcat: + case LibFunc_strncat: + Changed |= setReturnedArg(F, 0); + LLVM_FALLTHROUGH; + case LibFunc_stpcpy: + case LibFunc_stpncpy: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_strxfrm: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_strcmp: // 0,1 + case LibFunc_strspn: // 0,1 + case LibFunc_strncmp: // 0,1 + case LibFunc_strcspn: // 0,1 + case LibFunc_strcoll: // 0,1 + case LibFunc_strcasecmp: // 0,1 + case LibFunc_strncasecmp: // + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_strstr: + case LibFunc_strpbrk: + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_strtok: + case LibFunc_strtok_r: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_scanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_setbuf: + case LibFunc_setvbuf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_strdup: + case LibFunc_strndup: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_stat: + case LibFunc_statvfs: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_sscanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_sprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_snprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotCapture(F, 2); + Changed |= setOnlyReadsMemory(F, 2); + return Changed; + case LibFunc_setitimer: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setDoesNotCapture(F, 2); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_system: + // May throw; "system" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_malloc: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_memcmp: + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_memchr: + case LibFunc_memrchr: + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotThrow(F); + return Changed; + case LibFunc_modf: + case LibFunc_modff: + case LibFunc_modfl: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_memcpy: + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotAlias(F, 1); + Changed |= setReturnedArg(F, 0); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_memmove: + Changed |= setReturnedArg(F, 0); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_mempcpy: + case LibFunc_memccpy: + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotAlias(F, 1); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_memcpy_chk: + Changed |= setDoesNotThrow(F); + return Changed; + case LibFunc_memalign: + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_mkdir: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_mktime: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_realloc: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_read: + // May throw; "read" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_rewind: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_rmdir: + case LibFunc_remove: + case LibFunc_realpath: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_rename: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_readlink: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_write: + // May throw; "write" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_bcopy: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_bcmp: + Changed |= setDoesNotThrow(F); + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_bzero: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_calloc: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_chmod: + case LibFunc_chown: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_ctermid: + case LibFunc_clearerr: + case LibFunc_closedir: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_atoi: + case LibFunc_atol: + case LibFunc_atof: + case LibFunc_atoll: + Changed |= setDoesNotThrow(F); + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_access: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_fopen: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_fdopen: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_feof: + case LibFunc_free: + case LibFunc_fseek: + case LibFunc_ftell: + case LibFunc_fgetc: + case LibFunc_fgetc_unlocked: + case LibFunc_fseeko: + case LibFunc_ftello: + case LibFunc_fileno: + case LibFunc_fflush: + case LibFunc_fclose: + case LibFunc_fsetpos: + case LibFunc_flockfile: + case LibFunc_funlockfile: + case LibFunc_ftrylockfile: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_ferror: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F); + return Changed; + case LibFunc_fputc: + case LibFunc_fputc_unlocked: + case LibFunc_fstat: + case LibFunc_frexp: + case LibFunc_frexpf: + case LibFunc_frexpl: + case LibFunc_fstatvfs: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_fgets: + case LibFunc_fgets_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 2); + return Changed; + case LibFunc_fread: + case LibFunc_fread_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 3); + return Changed; + case LibFunc_fwrite: + case LibFunc_fwrite_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 3); + // FIXME: readonly #1? + return Changed; + case LibFunc_fputs: + case LibFunc_fputs_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_fscanf: + case LibFunc_fprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_fgetpos: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_getc: + case LibFunc_getlogin_r: + case LibFunc_getc_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_getenv: + Changed |= setDoesNotThrow(F); + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_gets: + case LibFunc_getchar: + case LibFunc_getchar_unlocked: + Changed |= setDoesNotThrow(F); + return Changed; + case LibFunc_getitimer: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_getpwnam: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_ungetc: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_uname: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_unlink: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_unsetenv: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_utime: + case LibFunc_utimes: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_putc: + case LibFunc_putc_unlocked: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_puts: + case LibFunc_printf: + case LibFunc_perror: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_pread: + // May throw; "pread" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_pwrite: + // May throw; "pwrite" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_putchar: + case LibFunc_putchar_unlocked: + Changed |= setDoesNotThrow(F); + return Changed; + case LibFunc_popen: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_pclose: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_vscanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_vsscanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_vfscanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_valloc: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_vprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_vfprintf: + case LibFunc_vsprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_vsnprintf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 2); + Changed |= setOnlyReadsMemory(F, 2); + return Changed; + case LibFunc_open: + // May throw; "open" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_opendir: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_tmpfile: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_times: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_htonl: + case LibFunc_htons: + case LibFunc_ntohl: + case LibFunc_ntohs: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotAccessMemory(F); + return Changed; + case LibFunc_lstat: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_lchown: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_qsort: + // May throw; places call through function pointer. + Changed |= setDoesNotCapture(F, 3); + return Changed; + case LibFunc_dunder_strdup: + case LibFunc_dunder_strndup: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_dunder_strtok_r: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_under_IO_getc: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_under_IO_putc: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_dunder_isoc99_scanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_stat64: + case LibFunc_lstat64: + case LibFunc_statvfs64: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_dunder_isoc99_sscanf: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_fopen64: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + case LibFunc_fseeko64: + case LibFunc_ftello64: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_tmpfile64: + Changed |= setDoesNotThrow(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + case LibFunc_fstat64: + case LibFunc_fstatvfs64: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_open64: + // May throw; "open" is a valid pthread cancellation point. + Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyReadsMemory(F, 0); + return Changed; + case LibFunc_gettimeofday: + // Currently some platforms have the restrict keyword on the arguments to + // gettimeofday. To be conservative, do not add noalias to gettimeofday's + // arguments. + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_Znwj: // new(unsigned int) + case LibFunc_Znwm: // new(unsigned long) + case LibFunc_Znaj: // new[](unsigned int) + case LibFunc_Znam: // new[](unsigned long) + case LibFunc_msvc_new_int: // new(unsigned int) + case LibFunc_msvc_new_longlong: // new(unsigned long long) + case LibFunc_msvc_new_array_int: // new[](unsigned int) + case LibFunc_msvc_new_array_longlong: // new[](unsigned long long) + // Operator new always returns a nonnull noalias pointer + Changed |= setRetNonNull(F); + Changed |= setRetDoesNotAlias(F); + return Changed; + // TODO: add LibFunc entries for: + // case LibFunc_memset_pattern4: + // case LibFunc_memset_pattern8: + case LibFunc_memset_pattern16: + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyReadsMemory(F, 1); + return Changed; + // int __nvvm_reflect(const char *) + case LibFunc_nvvm_reflect: + Changed |= setDoesNotAccessMemory(F); + Changed |= setDoesNotThrow(F); + return Changed; + + default: + // FIXME: It'd be really nice to cover all the library functions we're + // aware of here. + return false; + } +} + +bool llvm::hasFloatFn(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, LibFunc LongDoubleFn) { + switch (Ty->getTypeID()) { + case Type::HalfTyID: + return false; + case Type::FloatTyID: + return TLI->has(FloatFn); + case Type::DoubleTyID: + return TLI->has(DoubleFn); + default: + return TLI->has(LongDoubleFn); + } +} + +StringRef llvm::getFloatFnName(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn) { + assert(hasFloatFn(TLI, Ty, DoubleFn, FloatFn, LongDoubleFn) && + "Cannot get name for unavailable function!"); + + switch (Ty->getTypeID()) { + case Type::HalfTyID: + llvm_unreachable("No name for HalfTy!"); + case Type::FloatTyID: + return TLI->getName(FloatFn); + case Type::DoubleTyID: + return TLI->getName(DoubleFn); + default: + return TLI->getName(LongDoubleFn); + } +} + +//- Emit LibCalls ------------------------------------------------------------// + +Value *llvm::castToCStr(Value *V, IRBuilder<> &B) { + unsigned AS = V->getType()->getPointerAddressSpace(); + return B.CreateBitCast(V, B.getInt8PtrTy(AS), "cstr"); +} + +static Value *emitLibCall(LibFunc TheLibFunc, Type *ReturnType, + ArrayRef<Type *> ParamTypes, + ArrayRef<Value *> Operands, IRBuilder<> &B, + const TargetLibraryInfo *TLI, + bool IsVaArgs = false) { + if (!TLI->has(TheLibFunc)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FuncName = TLI->getName(TheLibFunc); + FunctionType *FuncType = FunctionType::get(ReturnType, ParamTypes, IsVaArgs); + FunctionCallee Callee = M->getOrInsertFunction(FuncName, FuncType); + inferLibFuncAttributes(M, FuncName, *TLI); + CallInst *CI = B.CreateCall(Callee, Operands, FuncName); + if (const Function *F = + dyn_cast<Function>(Callee.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + +Value *llvm::emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall(LibFunc_strlen, DL.getIntPtrType(Context), + B.getInt8PtrTy(), castToCStr(Ptr, B), B, TLI); +} + +Value *llvm::emitStrDup(Value *Ptr, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strdup, B.getInt8PtrTy(), B.getInt8PtrTy(), + castToCStr(Ptr, B), B, TLI); +} + +Value *llvm::emitStrChr(Value *Ptr, char C, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + Type *I32Ty = B.getInt32Ty(); + return emitLibCall(LibFunc_strchr, I8Ptr, {I8Ptr, I32Ty}, + {castToCStr(Ptr, B), ConstantInt::get(I32Ty, C)}, B, TLI); +} + +Value *llvm::emitStrNCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_strncmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); +} + +Value *llvm::emitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_strcpy, I8Ptr, {I8Ptr, I8Ptr}, + {castToCStr(Dst, B), castToCStr(Src, B)}, B, TLI); +} + +Value *llvm::emitStpCpy(Value *Dst, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_stpcpy, I8Ptr, {I8Ptr, I8Ptr}, + {castToCStr(Dst, B), castToCStr(Src, B)}, B, TLI); +} + +Value *llvm::emitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_strncpy, I8Ptr, {I8Ptr, I8Ptr, Len->getType()}, + {castToCStr(Dst, B), castToCStr(Src, B), Len}, B, TLI); +} + +Value *llvm::emitStpNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + Type *I8Ptr = B.getInt8PtrTy(); + return emitLibCall(LibFunc_stpncpy, I8Ptr, {I8Ptr, I8Ptr, Len->getType()}, + {castToCStr(Dst, B), castToCStr(Src, B), Len}, B, TLI); +} + +Value *llvm::emitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_memcpy_chk)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + AttributeList AS; + AS = AttributeList::get(M->getContext(), AttributeList::FunctionIndex, + Attribute::NoUnwind); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + FunctionCallee MemCpy = M->getOrInsertFunction( + "__memcpy_chk", AttributeList::get(M->getContext(), AS), B.getInt8PtrTy(), + B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context), + DL.getIntPtrType(Context)); + Dst = castToCStr(Dst, B); + Src = castToCStr(Src, B); + CallInst *CI = B.CreateCall(MemCpy, {Dst, Src, Len, ObjSize}); + if (const Function *F = + dyn_cast<Function>(MemCpy.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + +Value *llvm::emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_memchr, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt32Ty(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr, B), Val, Len}, B, TLI); +} + +Value *llvm::emitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_memcmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); +} + +Value *llvm::emitBCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_bcmp, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, B, TLI); +} + +Value *llvm::emitMemCCpy(Value *Ptr1, Value *Ptr2, Value *Val, Value *Len, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall( + LibFunc_memccpy, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), B.getInt32Ty(), Len->getType()}, + {Ptr1, Ptr2, Val, Len}, B, TLI); +} + +Value *llvm::emitSNPrintf(Value *Dest, Value *Size, Value *Fmt, + ArrayRef<Value *> VariadicArgs, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + SmallVector<Value *, 8> Args{castToCStr(Dest, B), Size, castToCStr(Fmt, B)}; + Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + return emitLibCall(LibFunc_snprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), Size->getType(), B.getInt8PtrTy()}, + Args, B, TLI, /*IsVaArgs=*/true); +} + +Value *llvm::emitSPrintf(Value *Dest, Value *Fmt, + ArrayRef<Value *> VariadicArgs, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + SmallVector<Value *, 8> Args{castToCStr(Dest, B), castToCStr(Fmt, B)}; + Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + return emitLibCall(LibFunc_sprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy()}, Args, B, TLI, + /*IsVaArgs=*/true); +} + +Value *llvm::emitStrCat(Value *Dest, Value *Src, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strcat, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy()}, + {castToCStr(Dest, B), castToCStr(Src, B)}, B, TLI); +} + +Value *llvm::emitStrLCpy(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strlcpy, Size->getType(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitStrLCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strlcat, Size->getType(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitStrNCat(Value *Dest, Value *Src, Value *Size, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_strncat, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), Size->getType()}, + {castToCStr(Dest, B), castToCStr(Src, B), Size}, B, TLI); +} + +Value *llvm::emitVSNPrintf(Value *Dest, Value *Size, Value *Fmt, Value *VAList, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall( + LibFunc_vsnprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), Size->getType(), B.getInt8PtrTy(), VAList->getType()}, + {castToCStr(Dest, B), Size, castToCStr(Fmt, B), VAList}, B, TLI); +} + +Value *llvm::emitVSPrintf(Value *Dest, Value *Fmt, Value *VAList, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + return emitLibCall(LibFunc_vsprintf, B.getInt32Ty(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), VAList->getType()}, + {castToCStr(Dest, B), castToCStr(Fmt, B), VAList}, B, TLI); +} + +/// Append a suffix to the function name according to the type of 'Op'. +static void appendTypeSuffix(Value *Op, StringRef &Name, + SmallString<20> &NameBuffer) { + if (!Op->getType()->isDoubleTy()) { + NameBuffer += Name; + + if (Op->getType()->isFloatTy()) + NameBuffer += 'f'; + else + NameBuffer += 'l'; + + Name = NameBuffer; + } +} + +static Value *emitUnaryFloatFnCallHelper(Value *Op, StringRef Name, + IRBuilder<> &B, + const AttributeList &Attrs) { + assert((Name != "") && "Must specify Name to emitUnaryFloatFnCall"); + + Module *M = B.GetInsertBlock()->getModule(); + FunctionCallee Callee = + M->getOrInsertFunction(Name, Op->getType(), Op->getType()); + CallInst *CI = B.CreateCall(Callee, Op, Name); + + // The incoming attribute set may have come from a speculatable intrinsic, but + // is being replaced with a library call which is not allowed to be + // speculatable. + CI->setAttributes(Attrs.removeAttribute(B.getContext(), + AttributeList::FunctionIndex, + Attribute::Speculatable)); + if (const Function *F = + dyn_cast<Function>(Callee.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; +} + +Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, + const AttributeList &Attrs) { + SmallString<20> NameBuffer; + appendTypeSuffix(Op, Name, NameBuffer); + + return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs); +} + +Value *llvm::emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn, IRBuilder<> &B, + const AttributeList &Attrs) { + // Get the name of the function according to TLI. + StringRef Name = getFloatFnName(TLI, Op->getType(), + DoubleFn, FloatFn, LongDoubleFn); + + return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs); +} + +static Value *emitBinaryFloatFnCallHelper(Value *Op1, Value *Op2, + StringRef Name, IRBuilder<> &B, + const AttributeList &Attrs) { + assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall"); + + Module *M = B.GetInsertBlock()->getModule(); + FunctionCallee Callee = M->getOrInsertFunction(Name, Op1->getType(), + Op1->getType(), Op2->getType()); + CallInst *CI = B.CreateCall(Callee, { Op1, Op2 }, Name); + + // The incoming attribute set may have come from a speculatable intrinsic, but + // is being replaced with a library call which is not allowed to be + // speculatable. + CI->setAttributes(Attrs.removeAttribute(B.getContext(), + AttributeList::FunctionIndex, + Attribute::Speculatable)); + if (const Function *F = + dyn_cast<Function>(Callee.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; +} + +Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, + IRBuilder<> &B, const AttributeList &Attrs) { + assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall"); + + SmallString<20> NameBuffer; + appendTypeSuffix(Op1, Name, NameBuffer); + + return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs); +} + +Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, + const TargetLibraryInfo *TLI, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn, IRBuilder<> &B, + const AttributeList &Attrs) { + // Get the name of the function according to TLI. + StringRef Name = getFloatFnName(TLI, Op1->getType(), + DoubleFn, FloatFn, LongDoubleFn); + + return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs); +} + +Value *llvm::emitPutChar(Value *Char, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_putchar)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef PutCharName = TLI->getName(LibFunc_putchar); + FunctionCallee PutChar = + M->getOrInsertFunction(PutCharName, B.getInt32Ty(), B.getInt32Ty()); + inferLibFuncAttributes(M, PutCharName, *TLI); + CallInst *CI = B.CreateCall(PutChar, + B.CreateIntCast(Char, + B.getInt32Ty(), + /*isSigned*/true, + "chari"), + PutCharName); + + if (const Function *F = + dyn_cast<Function>(PutChar.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + +Value *llvm::emitPutS(Value *Str, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_puts)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef PutsName = TLI->getName(LibFunc_puts); + FunctionCallee PutS = + M->getOrInsertFunction(PutsName, B.getInt32Ty(), B.getInt8PtrTy()); + inferLibFuncAttributes(M, PutsName, *TLI); + CallInst *CI = B.CreateCall(PutS, castToCStr(Str, B), PutsName); + if (const Function *F = + dyn_cast<Function>(PutS.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + return CI; +} + +Value *llvm::emitFPutC(Value *Char, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputc)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FPutcName = TLI->getName(LibFunc_fputc); + FunctionCallee F = M->getOrInsertFunction(FPutcName, B.getInt32Ty(), + B.getInt32Ty(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FPutcName, *TLI); + Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/true, + "chari"); + CallInst *CI = B.CreateCall(F, {Char, File}, FPutcName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFPutCUnlocked(Value *Char, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputc_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FPutcUnlockedName = TLI->getName(LibFunc_fputc_unlocked); + FunctionCallee F = M->getOrInsertFunction(FPutcUnlockedName, B.getInt32Ty(), + B.getInt32Ty(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FPutcUnlockedName, *TLI); + Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/ true, "chari"); + CallInst *CI = B.CreateCall(F, {Char, File}, FPutcUnlockedName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFPutS(Value *Str, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputs)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FPutsName = TLI->getName(LibFunc_fputs); + FunctionCallee F = M->getOrInsertFunction(FPutsName, B.getInt32Ty(), + B.getInt8PtrTy(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FPutsName, *TLI); + CallInst *CI = B.CreateCall(F, {castToCStr(Str, B), File}, FPutsName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFPutSUnlocked(Value *Str, Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fputs_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FPutsUnlockedName = TLI->getName(LibFunc_fputs_unlocked); + FunctionCallee F = M->getOrInsertFunction(FPutsUnlockedName, B.getInt32Ty(), + B.getInt8PtrTy(), File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FPutsUnlockedName, *TLI); + CallInst *CI = B.CreateCall(F, {castToCStr(Str, B), File}, FPutsUnlockedName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFWrite(Value *Ptr, Value *Size, Value *File, IRBuilder<> &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fwrite)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + StringRef FWriteName = TLI->getName(LibFunc_fwrite); + FunctionCallee F = M->getOrInsertFunction( + FWriteName, DL.getIntPtrType(Context), B.getInt8PtrTy(), + DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); + + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FWriteName, *TLI); + CallInst *CI = + B.CreateCall(F, {castToCStr(Ptr, B), Size, + ConstantInt::get(DL.getIntPtrType(Context), 1), File}); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitMalloc(Value *Num, IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_malloc)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef MallocName = TLI->getName(LibFunc_malloc); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + FunctionCallee Malloc = M->getOrInsertFunction(MallocName, B.getInt8PtrTy(), + DL.getIntPtrType(Context)); + inferLibFuncAttributes(M, MallocName, *TLI); + CallInst *CI = B.CreateCall(Malloc, Num, MallocName); + + if (const Function *F = + dyn_cast<Function>(Malloc.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; +} + +Value *llvm::emitCalloc(Value *Num, Value *Size, const AttributeList &Attrs, + IRBuilder<> &B, const TargetLibraryInfo &TLI) { + if (!TLI.has(LibFunc_calloc)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef CallocName = TLI.getName(LibFunc_calloc); + const DataLayout &DL = M->getDataLayout(); + IntegerType *PtrType = DL.getIntPtrType((B.GetInsertBlock()->getContext())); + FunctionCallee Calloc = M->getOrInsertFunction( + CallocName, Attrs, B.getInt8PtrTy(), PtrType, PtrType); + inferLibFuncAttributes(M, CallocName, TLI); + CallInst *CI = B.CreateCall(Calloc, {Num, Size}, CallocName); + + if (const auto *F = + dyn_cast<Function>(Calloc.getCallee()->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; +} + +Value *llvm::emitFWriteUnlocked(Value *Ptr, Value *Size, Value *N, Value *File, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fwrite_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + StringRef FWriteUnlockedName = TLI->getName(LibFunc_fwrite_unlocked); + FunctionCallee F = M->getOrInsertFunction( + FWriteUnlockedName, DL.getIntPtrType(Context), B.getInt8PtrTy(), + DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); + + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FWriteUnlockedName, *TLI); + CallInst *CI = B.CreateCall(F, {castToCStr(Ptr, B), Size, N, File}); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFGetCUnlocked(Value *File, IRBuilder<> &B, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fgetc_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FGetCUnlockedName = TLI->getName(LibFunc_fgetc_unlocked); + FunctionCallee F = M->getOrInsertFunction(FGetCUnlockedName, B.getInt32Ty(), + File->getType()); + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FGetCUnlockedName, *TLI); + CallInst *CI = B.CreateCall(F, File, FGetCUnlockedName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFGetSUnlocked(Value *Str, Value *Size, Value *File, + IRBuilder<> &B, const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fgets_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + StringRef FGetSUnlockedName = TLI->getName(LibFunc_fgets_unlocked); + FunctionCallee F = + M->getOrInsertFunction(FGetSUnlockedName, B.getInt8PtrTy(), + B.getInt8PtrTy(), B.getInt32Ty(), File->getType()); + inferLibFuncAttributes(M, FGetSUnlockedName, *TLI); + CallInst *CI = + B.CreateCall(F, {castToCStr(Str, B), Size, File}, FGetSUnlockedName); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} + +Value *llvm::emitFReadUnlocked(Value *Ptr, Value *Size, Value *N, Value *File, + IRBuilder<> &B, const DataLayout &DL, + const TargetLibraryInfo *TLI) { + if (!TLI->has(LibFunc_fread_unlocked)) + return nullptr; + + Module *M = B.GetInsertBlock()->getModule(); + LLVMContext &Context = B.GetInsertBlock()->getContext(); + StringRef FReadUnlockedName = TLI->getName(LibFunc_fread_unlocked); + FunctionCallee F = M->getOrInsertFunction( + FReadUnlockedName, DL.getIntPtrType(Context), B.getInt8PtrTy(), + DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType()); + + if (File->getType()->isPointerTy()) + inferLibFuncAttributes(M, FReadUnlockedName, *TLI); + CallInst *CI = B.CreateCall(F, {castToCStr(Ptr, B), Size, N, File}); + + if (const Function *Fn = + dyn_cast<Function>(F.getCallee()->stripPointerCasts())) + CI->setCallingConv(Fn->getCallingConv()); + return CI; +} |