mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-11 04:01:01 +00:00

Now the pass is just a tiny wrapper around the util. This lets us reuse the logic elsewhere (done here for BuildLibCalls) instead of duplicating it. The next step is to have something like getOrInsertLibFunc that also sets the attributes. Differential Revision: http://reviews.llvm.org/D19470 llvm-svn: 267759
1006 lines
33 KiB
C++
1006 lines
33 KiB
C++
//===- BuildLibCalls.cpp - Utility builder for libcalls -------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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"
|
|
|
|
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");
|
|
|
|
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 setDoesNotCapture(Function &F, unsigned n) {
|
|
if (F.doesNotCapture(n))
|
|
return false;
|
|
F.setDoesNotCapture(n);
|
|
++NumNoCapture;
|
|
return true;
|
|
}
|
|
|
|
static bool setOnlyReadsMemory(Function &F, unsigned n) {
|
|
if (F.onlyReadsMemory(n))
|
|
return false;
|
|
F.setOnlyReadsMemory(n);
|
|
++NumReadOnlyArg;
|
|
return true;
|
|
}
|
|
|
|
static bool setDoesNotAlias(Function &F, unsigned n) {
|
|
if (F.doesNotAlias(n))
|
|
return false;
|
|
F.setDoesNotAlias(n);
|
|
++NumNoAlias;
|
|
return true;
|
|
}
|
|
|
|
static bool setNonNull(Function &F, unsigned n) {
|
|
assert((n != AttributeSet::ReturnIndex ||
|
|
F.getReturnType()->isPointerTy()) &&
|
|
"nonnull applies only to pointers");
|
|
if (F.getAttributes().hasAttribute(n, Attribute::NonNull))
|
|
return false;
|
|
F.addAttribute(n, Attribute::NonNull);
|
|
++NumNonNull;
|
|
return true;
|
|
}
|
|
|
|
bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
|
|
LibFunc::Func TheLibFunc;
|
|
if (!(TLI.getLibFunc(F, TheLibFunc) && TLI.has(TheLibFunc)))
|
|
return false;
|
|
|
|
bool Changed = false;
|
|
switch (TheLibFunc) {
|
|
case LibFunc::strlen:
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
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, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::strcpy:
|
|
case LibFunc::stpcpy:
|
|
case LibFunc::strcat:
|
|
case LibFunc::strncat:
|
|
case LibFunc::strncpy:
|
|
case LibFunc::stpncpy:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::strxfrm:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
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, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::strstr:
|
|
case LibFunc::strpbrk:
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::strtok:
|
|
case LibFunc::strtok_r:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::scanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::setbuf:
|
|
case LibFunc::setvbuf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::strdup:
|
|
case LibFunc::strndup:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::stat:
|
|
case LibFunc::statvfs:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::sscanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::sprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::snprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 3);
|
|
Changed |= setOnlyReadsMemory(F, 3);
|
|
return Changed;
|
|
case LibFunc::setitimer:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setDoesNotCapture(F, 3);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::system:
|
|
// May throw; "system" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::malloc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::memcmp:
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
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, 2);
|
|
return Changed;
|
|
case LibFunc::memcpy:
|
|
case LibFunc::memccpy:
|
|
case LibFunc::memmove:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::memcpy_chk:
|
|
Changed |= setDoesNotThrow(F);
|
|
return Changed;
|
|
case LibFunc::memalign:
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::mkdir:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::mktime:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::realloc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::read:
|
|
// May throw; "read" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::rewind:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::rmdir:
|
|
case LibFunc::remove:
|
|
case LibFunc::realpath:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::rename:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::readlink:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::write:
|
|
// May throw; "write" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::bcopy:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::bcmp:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::bzero:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::calloc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::chmod:
|
|
case LibFunc::chown:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::ctermid:
|
|
case LibFunc::clearerr:
|
|
case LibFunc::closedir:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::atoi:
|
|
case LibFunc::atol:
|
|
case LibFunc::atof:
|
|
case LibFunc::atoll:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::access:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::fopen:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::fdopen:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::feof:
|
|
case LibFunc::free:
|
|
case LibFunc::fseek:
|
|
case LibFunc::ftell:
|
|
case LibFunc::fgetc:
|
|
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, 1);
|
|
return Changed;
|
|
case LibFunc::ferror:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F);
|
|
return Changed;
|
|
case LibFunc::fputc:
|
|
case LibFunc::fstat:
|
|
case LibFunc::frexp:
|
|
case LibFunc::frexpf:
|
|
case LibFunc::frexpl:
|
|
case LibFunc::fstatvfs:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::fgets:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 3);
|
|
return Changed;
|
|
case LibFunc::fread:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 4);
|
|
return Changed;
|
|
case LibFunc::fwrite:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 4);
|
|
// FIXME: readonly #1?
|
|
return Changed;
|
|
case LibFunc::fputs:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::fscanf:
|
|
case LibFunc::fprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::fgetpos:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::getc:
|
|
case LibFunc::getlogin_r:
|
|
case LibFunc::getc_unlocked:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::getenv:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setOnlyReadsMemory(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::gets:
|
|
case LibFunc::getchar:
|
|
Changed |= setDoesNotThrow(F);
|
|
return Changed;
|
|
case LibFunc::getitimer:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::getpwnam:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::ungetc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::uname:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::unlink:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::unsetenv:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::utime:
|
|
case LibFunc::utimes:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::putc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::puts:
|
|
case LibFunc::printf:
|
|
case LibFunc::perror:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::pread:
|
|
// May throw; "pread" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::pwrite:
|
|
// May throw; "pwrite" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::putchar:
|
|
Changed |= setDoesNotThrow(F);
|
|
return Changed;
|
|
case LibFunc::popen:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::pclose:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::vscanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::vsscanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::vfscanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::valloc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::vprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::vfprintf:
|
|
case LibFunc::vsprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::vsnprintf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 3);
|
|
Changed |= setOnlyReadsMemory(F, 3);
|
|
return Changed;
|
|
case LibFunc::open:
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::opendir:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::tmpfile:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::times:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
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, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::lchown:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::qsort:
|
|
// May throw; places call through function pointer.
|
|
Changed |= setDoesNotCapture(F, 4);
|
|
return Changed;
|
|
case LibFunc::dunder_strdup:
|
|
case LibFunc::dunder_strndup:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::dunder_strtok_r:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::under_IO_getc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::under_IO_putc:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::dunder_isoc99_scanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::stat64:
|
|
case LibFunc::lstat64:
|
|
case LibFunc::statvfs64:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
return Changed;
|
|
case LibFunc::dunder_isoc99_sscanf:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::fopen64:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
return Changed;
|
|
case LibFunc::fseeko64:
|
|
case LibFunc::ftello64:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
return Changed;
|
|
case LibFunc::tmpfile64:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotAlias(F, 0);
|
|
return Changed;
|
|
case LibFunc::fstat64:
|
|
case LibFunc::fstatvfs64:
|
|
Changed |= setDoesNotThrow(F);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
return Changed;
|
|
case LibFunc::open64:
|
|
// May throw; "open" is a valid pthread cancellation point.
|
|
Changed |= setDoesNotCapture(F, 1);
|
|
Changed |= setOnlyReadsMemory(F, 1);
|
|
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, 1);
|
|
Changed |= setDoesNotCapture(F, 2);
|
|
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 |= setNonNull(F, AttributeSet::ReturnIndex);
|
|
Changed |= setDoesNotAlias(F, AttributeSet::ReturnIndex);
|
|
return Changed;
|
|
//TODO: add LibFunc entries for:
|
|
//case LibFunc::memset_pattern4:
|
|
//case LibFunc::memset_pattern8:
|
|
case LibFunc::memset_pattern16:
|
|
Changed |= setOnlyAccessesArgMemory(F);
|
|
Changed |= setOnlyReadsMemory(F, 2);
|
|
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;
|
|
}
|
|
}
|
|
|
|
//- Emit LibCalls ------------------------------------------------------------//
|
|
|
|
Value *llvm::castToCStr(Value *V, IRBuilder<> &B) {
|
|
unsigned AS = V->getType()->getPointerAddressSpace();
|
|
return B.CreateBitCast(V, B.getInt8PtrTy(AS), "cstr");
|
|
}
|
|
|
|
Value *llvm::emitStrLen(Value *Ptr, IRBuilder<> &B, const DataLayout &DL,
|
|
const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::strlen))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
|
Constant *StrLen = M->getOrInsertFunction("strlen", DL.getIntPtrType(Context),
|
|
B.getInt8PtrTy(), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("strlen"), *TLI);
|
|
CallInst *CI = B.CreateCall(StrLen, castToCStr(Ptr, B), "strlen");
|
|
if (const Function *F = dyn_cast<Function>(StrLen->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitStrChr(Value *Ptr, char C, IRBuilder<> &B,
|
|
const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::strchr))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Type *I8Ptr = B.getInt8PtrTy();
|
|
Type *I32Ty = B.getInt32Ty();
|
|
Constant *StrChr =
|
|
M->getOrInsertFunction("strchr", I8Ptr, I8Ptr, I32Ty, nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("strchr"), *TLI);
|
|
CallInst *CI = B.CreateCall(
|
|
StrChr, {castToCStr(Ptr, B), ConstantInt::get(I32Ty, C)}, "strchr");
|
|
if (const Function *F = dyn_cast<Function>(StrChr->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitStrNCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B,
|
|
const DataLayout &DL, const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::strncmp))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
|
Value *StrNCmp = M->getOrInsertFunction("strncmp", B.getInt32Ty(),
|
|
B.getInt8PtrTy(), B.getInt8PtrTy(),
|
|
DL.getIntPtrType(Context), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("strncmp"), *TLI);
|
|
CallInst *CI = B.CreateCall(
|
|
StrNCmp, {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, "strncmp");
|
|
|
|
if (const Function *F = dyn_cast<Function>(StrNCmp->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitStrCpy(Value *Dst, Value *Src, IRBuilder<> &B,
|
|
const TargetLibraryInfo *TLI, StringRef Name) {
|
|
if (!TLI->has(LibFunc::strcpy))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Type *I8Ptr = B.getInt8PtrTy();
|
|
Value *StrCpy = M->getOrInsertFunction(Name, I8Ptr, I8Ptr, I8Ptr, nullptr);
|
|
inferLibFuncAttributes(*M->getFunction(Name), *TLI);
|
|
CallInst *CI =
|
|
B.CreateCall(StrCpy, {castToCStr(Dst, B), castToCStr(Src, B)}, Name);
|
|
if (const Function *F = dyn_cast<Function>(StrCpy->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B,
|
|
const TargetLibraryInfo *TLI, StringRef Name) {
|
|
if (!TLI->has(LibFunc::strncpy))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Type *I8Ptr = B.getInt8PtrTy();
|
|
Value *StrNCpy = M->getOrInsertFunction(Name, I8Ptr, I8Ptr, I8Ptr,
|
|
Len->getType(), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction(Name), *TLI);
|
|
CallInst *CI = B.CreateCall(
|
|
StrNCpy, {castToCStr(Dst, B), castToCStr(Src, B), Len}, "strncpy");
|
|
if (const Function *F = dyn_cast<Function>(StrNCpy->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
return CI;
|
|
}
|
|
|
|
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();
|
|
AttributeSet AS;
|
|
AS = AttributeSet::get(M->getContext(), AttributeSet::FunctionIndex,
|
|
Attribute::NoUnwind);
|
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
|
Value *MemCpy = M->getOrInsertFunction(
|
|
"__memcpy_chk", AttributeSet::get(M->getContext(), AS), B.getInt8PtrTy(),
|
|
B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context),
|
|
DL.getIntPtrType(Context), nullptr);
|
|
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->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B,
|
|
const DataLayout &DL, const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::memchr))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
|
Value *MemChr = M->getOrInsertFunction("memchr", B.getInt8PtrTy(),
|
|
B.getInt8PtrTy(), B.getInt32Ty(),
|
|
DL.getIntPtrType(Context), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("memchr"), *TLI);
|
|
CallInst *CI = B.CreateCall(MemChr, {castToCStr(Ptr, B), Val, Len}, "memchr");
|
|
|
|
if (const Function *F = dyn_cast<Function>(MemChr->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B,
|
|
const DataLayout &DL, const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::memcmp))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
LLVMContext &Context = B.GetInsertBlock()->getContext();
|
|
Value *MemCmp = M->getOrInsertFunction("memcmp", B.getInt32Ty(),
|
|
B.getInt8PtrTy(), B.getInt8PtrTy(),
|
|
DL.getIntPtrType(Context), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("memcmp"), *TLI);
|
|
CallInst *CI = B.CreateCall(
|
|
MemCmp, {castToCStr(Ptr1, B), castToCStr(Ptr2, B), Len}, "memcmp");
|
|
|
|
if (const Function *F = dyn_cast<Function>(MemCmp->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
}
|
|
|
|
Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
|
|
const AttributeSet &Attrs) {
|
|
SmallString<20> NameBuffer;
|
|
appendTypeSuffix(Op, Name, NameBuffer);
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
|
|
Op->getType(), nullptr);
|
|
CallInst *CI = B.CreateCall(Callee, Op, Name);
|
|
CI->setAttributes(Attrs);
|
|
if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
|
|
IRBuilder<> &B, const AttributeSet &Attrs) {
|
|
SmallString<20> NameBuffer;
|
|
appendTypeSuffix(Op1, Name, NameBuffer);
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Value *Callee = M->getOrInsertFunction(Name, Op1->getType(), Op1->getType(),
|
|
Op2->getType(), nullptr);
|
|
CallInst *CI = B.CreateCall(Callee, {Op1, Op2}, Name);
|
|
CI->setAttributes(Attrs);
|
|
if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
|
|
CI->setCallingConv(F->getCallingConv());
|
|
|
|
return CI;
|
|
}
|
|
|
|
Value *llvm::emitPutChar(Value *Char, IRBuilder<> &B,
|
|
const TargetLibraryInfo *TLI) {
|
|
if (!TLI->has(LibFunc::putchar))
|
|
return nullptr;
|
|
|
|
Module *M = B.GetInsertBlock()->getModule();
|
|
Value *PutChar = M->getOrInsertFunction("putchar", B.getInt32Ty(),
|
|
B.getInt32Ty(), nullptr);
|
|
CallInst *CI = B.CreateCall(PutChar,
|
|
B.CreateIntCast(Char,
|
|
B.getInt32Ty(),
|
|
/*isSigned*/true,
|
|
"chari"),
|
|
"putchar");
|
|
|
|
if (const Function *F = dyn_cast<Function>(PutChar->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();
|
|
Value *PutS =
|
|
M->getOrInsertFunction("puts", B.getInt32Ty(), B.getInt8PtrTy(), nullptr);
|
|
inferLibFuncAttributes(*M->getFunction("puts"), *TLI);
|
|
CallInst *CI = B.CreateCall(PutS, castToCStr(Str, B), "puts");
|
|
if (const Function *F = dyn_cast<Function>(PutS->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();
|
|
Constant *F = M->getOrInsertFunction("fputc", B.getInt32Ty(), B.getInt32Ty(),
|
|
File->getType(), nullptr);
|
|
if (File->getType()->isPointerTy())
|
|
inferLibFuncAttributes(*M->getFunction("fputc"), *TLI);
|
|
Char = B.CreateIntCast(Char, B.getInt32Ty(), /*isSigned*/true,
|
|
"chari");
|
|
CallInst *CI = B.CreateCall(F, {Char, File}, "fputc");
|
|
|
|
if (const Function *Fn = dyn_cast<Function>(F->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);
|
|
Constant *F = M->getOrInsertFunction(
|
|
FPutsName, B.getInt32Ty(), B.getInt8PtrTy(), File->getType(), nullptr);
|
|
if (File->getType()->isPointerTy())
|
|
inferLibFuncAttributes(*M->getFunction(FPutsName), *TLI);
|
|
CallInst *CI = B.CreateCall(F, {castToCStr(Str, B), File}, "fputs");
|
|
|
|
if (const Function *Fn = dyn_cast<Function>(F->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);
|
|
Constant *F = M->getOrInsertFunction(
|
|
FWriteName, DL.getIntPtrType(Context), B.getInt8PtrTy(),
|
|
DL.getIntPtrType(Context), DL.getIntPtrType(Context), File->getType(),
|
|
nullptr);
|
|
if (File->getType()->isPointerTy())
|
|
inferLibFuncAttributes(*M->getFunction(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->stripPointerCasts()))
|
|
CI->setCallingConv(Fn->getCallingConv());
|
|
return CI;
|
|
}
|