forked from OSchip/llvm-project
Add pthread_self function prototype and make it speculatable.
Summary: This allows pthread_self to be pulled out of a loop by LICM. Reviewers: hfinkel, arsenm, davide Reviewed By: davide Subscribers: davide, wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D32782 llvm-svn: 303495
This commit is contained in:
parent
36af8f4d42
commit
75af3af957
|
@ -938,6 +938,9 @@ TLI_DEFINE_STRING_INTERNAL("pread")
|
||||||
/// int printf(const char *format, ...);
|
/// int printf(const char *format, ...);
|
||||||
TLI_DEFINE_ENUM_INTERNAL(printf)
|
TLI_DEFINE_ENUM_INTERNAL(printf)
|
||||||
TLI_DEFINE_STRING_INTERNAL("printf")
|
TLI_DEFINE_STRING_INTERNAL("printf")
|
||||||
|
/// pthread_t pthread_self(void);
|
||||||
|
TLI_DEFINE_ENUM_INTERNAL(pthread_self)
|
||||||
|
TLI_DEFINE_STRING_INTERNAL("pthread_self")
|
||||||
/// int putc(int c, FILE *stream);
|
/// int putc(int c, FILE *stream);
|
||||||
TLI_DEFINE_ENUM_INTERNAL(putc)
|
TLI_DEFINE_ENUM_INTERNAL(putc)
|
||||||
TLI_DEFINE_STRING_INTERNAL("putc")
|
TLI_DEFINE_STRING_INTERNAL("putc")
|
||||||
|
|
|
@ -349,6 +349,9 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
|
||||||
TLI.setUnavailable(LibFunc_atoll);
|
TLI.setUnavailable(LibFunc_atoll);
|
||||||
TLI.setUnavailable(LibFunc_frexpf);
|
TLI.setUnavailable(LibFunc_frexpf);
|
||||||
TLI.setUnavailable(LibFunc_llabs);
|
TLI.setUnavailable(LibFunc_llabs);
|
||||||
|
|
||||||
|
// Win32 does *not* provide pthread_self.
|
||||||
|
TLI.setUnavailable(LibFunc_pthread_self);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (T.getOS()) {
|
switch (T.getOS()) {
|
||||||
|
@ -1263,6 +1266,12 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||||
FTy.getParamType(0)->isPointerTy() &&
|
FTy.getParamType(0)->isPointerTy() &&
|
||||||
FTy.getParamType(1) == SizeTTy && FTy.getParamType(2) == SizeTTy);
|
FTy.getParamType(1) == SizeTTy && FTy.getParamType(2) == SizeTTy);
|
||||||
|
|
||||||
|
// We do not attempt to match the return value here. i.e. thread identifiers
|
||||||
|
// should be considered opaque, for example, representation using either an
|
||||||
|
// arithmetic type or a structure is permitted.
|
||||||
|
case LibFunc_pthread_self:
|
||||||
|
return NumParams == 0;
|
||||||
|
|
||||||
case LibFunc_wcslen:
|
case LibFunc_wcslen:
|
||||||
return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() &&
|
return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() &&
|
||||||
FTy.getReturnType()->isIntegerTy());
|
FTy.getReturnType()->isIntegerTy());
|
||||||
|
|
|
@ -38,6 +38,7 @@ STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture");
|
||||||
STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly");
|
STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly");
|
||||||
STATISTIC(NumNoAlias, "Number of function returns inferred as noalias");
|
STATISTIC(NumNoAlias, "Number of function returns inferred as noalias");
|
||||||
STATISTIC(NumNonNull, "Number of function returns inferred as nonnull returns");
|
STATISTIC(NumNonNull, "Number of function returns inferred as nonnull returns");
|
||||||
|
STATISTIC(NumSpeculatable, "Number of functions inferred as speculatable");
|
||||||
|
|
||||||
static bool setDoesNotAccessMemory(Function &F) {
|
static bool setDoesNotAccessMemory(Function &F) {
|
||||||
if (F.doesNotAccessMemory())
|
if (F.doesNotAccessMemory())
|
||||||
|
@ -71,6 +72,14 @@ static bool setDoesNotThrow(Function &F) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool setSpeculatable(Function &F) {
|
||||||
|
if (F.isSpeculatable())
|
||||||
|
return false;
|
||||||
|
F.setSpeculatable();
|
||||||
|
++NumSpeculatable;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool setRetDoesNotAlias(Function &F) {
|
static bool setRetDoesNotAlias(Function &F) {
|
||||||
if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias))
|
if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias))
|
||||||
return false;
|
return false;
|
||||||
|
@ -530,6 +539,9 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
|
||||||
Changed |= setOnlyReadsMemory(F, 0);
|
Changed |= setOnlyReadsMemory(F, 0);
|
||||||
Changed |= setOnlyReadsMemory(F, 1);
|
Changed |= setOnlyReadsMemory(F, 1);
|
||||||
return Changed;
|
return Changed;
|
||||||
|
case LibFunc_pthread_self:
|
||||||
|
Changed |= setSpeculatable(F);
|
||||||
|
return Changed;
|
||||||
case LibFunc_vfscanf:
|
case LibFunc_vfscanf:
|
||||||
Changed |= setDoesNotThrow(F);
|
Changed |= setDoesNotThrow(F);
|
||||||
Changed |= setDoesNotCapture(F, 0);
|
Changed |= setDoesNotCapture(F, 0);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
; RUN: opt < %s -S -inferattrs -licm | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK-LABEL: define void @pthread_self_safe(
|
||||||
|
; CHECK-NEXT: call i64 @pthread_self()
|
||||||
|
define void @pthread_self_safe(i32) {
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:2: ; preds = %7, %1
|
||||||
|
%idx = phi i32 [ 0, %1 ], [ %8, %7 ]
|
||||||
|
%3 = icmp slt i32 %idx, %0
|
||||||
|
br i1 %3, label %4, label %9
|
||||||
|
|
||||||
|
; <label>:4: ; preds = %2
|
||||||
|
call void @external_func_that_could_do_anything()
|
||||||
|
%5 = call i64 @pthread_self() #1
|
||||||
|
%6 = trunc i64 %5 to i32
|
||||||
|
call void @use_pthread_self(i32 %6)
|
||||||
|
br label %7
|
||||||
|
|
||||||
|
; <label>:7: ; preds = %4
|
||||||
|
%8 = add nsw i32 %idx, 1
|
||||||
|
br label %2
|
||||||
|
|
||||||
|
; <label>:9: ; preds = %2
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: declare i64 @pthread_self() #0
|
||||||
|
; CHECK: attributes #0 = { nounwind readnone speculatable }
|
||||||
|
; Function Attrs: nounwind readnone
|
||||||
|
declare i64 @pthread_self() #1
|
||||||
|
|
||||||
|
declare void @external_func_that_could_do_anything()
|
||||||
|
|
||||||
|
declare void @use_pthread_self(i32)
|
||||||
|
|
||||||
|
attributes #1 = { nounwind readnone }
|
||||||
|
|
|
@ -63,12 +63,13 @@ TEST_F(TargetLibraryInfoTest, InvalidProto) {
|
||||||
parseAssembly("%foo = type { %foo }\n");
|
parseAssembly("%foo = type { %foo }\n");
|
||||||
|
|
||||||
auto *StructTy = M->getTypeByName("foo");
|
auto *StructTy = M->getTypeByName("foo");
|
||||||
auto *InvalidFTy = FunctionType::get(StructTy, /*isVarArg=*/false);
|
|
||||||
|
|
||||||
for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) {
|
for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) {
|
||||||
LibFunc LF = (LibFunc)FI;
|
LibFunc LF = (LibFunc)FI;
|
||||||
|
// Using the library function name to create a function that takes
|
||||||
|
// 1 parameter and returns the same type. There should be no library
|
||||||
|
// function that matches this egregiously incorrect prototypes.
|
||||||
auto *F = cast<Function>(
|
auto *F = cast<Function>(
|
||||||
M->getOrInsertFunction(TLI.getName(LF), InvalidFTy));
|
M->getOrInsertFunction(TLI.getName(LF), StructTy, StructTy));
|
||||||
EXPECT_FALSE(isLibFunc(F, LF));
|
EXPECT_FALSE(isLibFunc(F, LF));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,6 +247,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
|
||||||
"declare float @powf(float, float)\n"
|
"declare float @powf(float, float)\n"
|
||||||
"declare x86_fp80 @powl(x86_fp80, x86_fp80)\n"
|
"declare x86_fp80 @powl(x86_fp80, x86_fp80)\n"
|
||||||
"declare i32 @printf(i8*, ...)\n"
|
"declare i32 @printf(i8*, ...)\n"
|
||||||
|
"declare %struct @pthread_self()\n"
|
||||||
"declare i32 @putc(i32, %struct*)\n"
|
"declare i32 @putc(i32, %struct*)\n"
|
||||||
"declare i32 @putchar(i32)\n"
|
"declare i32 @putchar(i32)\n"
|
||||||
"declare i32 @puts(i8*)\n"
|
"declare i32 @puts(i8*)\n"
|
||||||
|
|
Loading…
Reference in New Issue