]> granicus.if.org Git - llvm/commitdiff
Add pthread_self function prototype and make it speculatable.
authorXin Tong <trent.xin.tong@gmail.com>
Sat, 20 May 2017 22:40:25 +0000 (22:40 +0000)
committerXin Tong <trent.xin.tong@gmail.com>
Sat, 20 May 2017 22:40:25 +0000 (22:40 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303495 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/TargetLibraryInfo.def
lib/Analysis/TargetLibraryInfo.cpp
lib/Transforms/Utils/BuildLibCalls.cpp
test/Transforms/LICM/pthread.ll [new file with mode: 0644]
unittests/Analysis/TargetLibraryInfoTest.cpp

index 9cbe917c146d956d0c72bd79bda4cb2475d232ae..be6685722d90698cbe52374759c8ba7812597b41 100644 (file)
@@ -938,6 +938,9 @@ TLI_DEFINE_STRING_INTERNAL("pread")
 /// int printf(const char *format, ...);
 TLI_DEFINE_ENUM_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);
 TLI_DEFINE_ENUM_INTERNAL(putc)
 TLI_DEFINE_STRING_INTERNAL("putc")
index 2be5d5caf7c2156e6859f329a8e036c4e2e48543..b12778278ce89b5aa20b64b73823f41132045b61 100644 (file)
@@ -349,6 +349,9 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
     TLI.setUnavailable(LibFunc_atoll);
     TLI.setUnavailable(LibFunc_frexpf);
     TLI.setUnavailable(LibFunc_llabs);
+
+    // Win32 does *not* provide pthread_self.
+    TLI.setUnavailable(LibFunc_pthread_self);
   }
 
   switch (T.getOS()) {
@@ -1263,6 +1266,12 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
             FTy.getParamType(0)->isPointerTy() &&
             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:
     return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() &&
             FTy.getReturnType()->isIntegerTy());
index ebde1f9a17dd6b0e459c795a5f967843ee2b32a2..cf3453252548b3974b7738981563bec5402204f0 100644 (file)
@@ -38,6 +38,7 @@ 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(NumSpeculatable, "Number of functions inferred as speculatable");
 
 static bool setDoesNotAccessMemory(Function &F) {
   if (F.doesNotAccessMemory())
@@ -71,6 +72,14 @@ static bool setDoesNotThrow(Function &F) {
   return true;
 }
 
+static bool setSpeculatable(Function &F) {
+  if (F.isSpeculatable())
+    return false;
+  F.setSpeculatable();
+  ++NumSpeculatable;
+  return true;
+}
+
 static bool setRetDoesNotAlias(Function &F) {
   if (F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias))
     return false;
@@ -530,6 +539,9 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     Changed |= setOnlyReadsMemory(F, 0);
     Changed |= setOnlyReadsMemory(F, 1);
     return Changed;
+  case LibFunc_pthread_self:
+    Changed |= setSpeculatable(F);
+    return Changed;
   case LibFunc_vfscanf:
     Changed |= setDoesNotThrow(F);
     Changed |= setDoesNotCapture(F, 0);
diff --git a/test/Transforms/LICM/pthread.ll b/test/Transforms/LICM/pthread.ll
new file mode 100644 (file)
index 0000000..6a7aa49
--- /dev/null
@@ -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 }
+
index 9d852cf0301b96b89014ad876e61c74bf9285d3f..64a735de6949d99d00dbcf47ca6063bbe477d902 100644 (file)
@@ -63,12 +63,13 @@ TEST_F(TargetLibraryInfoTest, InvalidProto) {
   parseAssembly("%foo = type { %foo }\n");
 
   auto *StructTy = M->getTypeByName("foo");
-  auto *InvalidFTy = FunctionType::get(StructTy, /*isVarArg=*/false);
-
   for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++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>(
-        M->getOrInsertFunction(TLI.getName(LF), InvalidFTy));
+        M->getOrInsertFunction(TLI.getName(LF), StructTy, StructTy));
     EXPECT_FALSE(isLibFunc(F, LF));
   }
 }
@@ -246,6 +247,7 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
     "declare float @powf(float, float)\n"
     "declare x86_fp80 @powl(x86_fp80, x86_fp80)\n"
     "declare i32 @printf(i8*, ...)\n"
+    "declare %struct @pthread_self()\n"
     "declare i32 @putc(i32, %struct*)\n"
     "declare i32 @putchar(i32)\n"
     "declare i32 @puts(i8*)\n"