[llvm] 65e94cc - [InferAttrs] Add argmemonly attribute to string libcalls

Dávid Bolvanský via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 17 16:33:42 PDT 2020


Author: Dávid Bolvanský
Date: 2020-10-18T01:33:26+02:00
New Revision: 65e94cc946b0109bc4e1150a9a46d104317cc940

URL: https://github.com/llvm/llvm-project/commit/65e94cc946b0109bc4e1150a9a46d104317cc940
DIFF: https://github.com/llvm/llvm-project/commit/65e94cc946b0109bc4e1150a9a46d104317cc940.diff

LOG: [InferAttrs] Add argmemonly attribute to string libcalls

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D89602

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/BuildLibCalls.cpp
    llvm/test/Transforms/InferFunctionAttrs/annotate.ll

Removed: 
    compiler-rt/test/asan/TestCases/strcat-overlap.cpp
    compiler-rt/test/asan/TestCases/strcpy-overlap.cpp
    compiler-rt/test/asan/TestCases/strncat-overlap.cpp
    compiler-rt/test/asan/TestCases/strncpy-overlap.cpp


################################################################################
diff  --git a/compiler-rt/test/asan/TestCases/strcat-overlap.cpp b/compiler-rt/test/asan/TestCases/strcat-overlap.cpp
deleted file mode 100644
index d3dd2a7c0347..000000000000
--- a/compiler-rt/test/asan/TestCases/strcat-overlap.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-
-// This test when run with suppressions invokes undefined
-// behavior which can cause all sorts of bad things to happen
-// depending on how strcat() is implemented. For now only run
-// on platforms where we know the test passes.
-// REQUIRES: x86_64h-darwin || x86_64-darwin || i386-darwin || x86_64-linux || i386-linux
-// UNSUPPORTED: windows-msvc
-// UNSUPPORTED: android
-
-#include <string.h>
-
-
-// Don't inline function otherwise stacktrace changes.
-__attribute__((noinline)) void bad_function() {
-  char buffer[] = "hello\0XXX";
-  // CHECK: strcat-param-overlap: memory ranges
-  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
-  // CHECK: {{#0 0x.* in .*strcat}}
-  // CHECK: {{#1 0x.* in bad_function.*strcat-overlap.cpp:}}[[@LINE+2]]
-  // CHECK: {{#2 0x.* in main .*strcat-overlap.cpp:}}[[@LINE+5]]
-  strcat(buffer, buffer + 1); // BOOM
-}
-
-int main(int argc, char **argv) {
-  bad_function();
-  return 0;
-}

diff  --git a/compiler-rt/test/asan/TestCases/strcpy-overlap.cpp b/compiler-rt/test/asan/TestCases/strcpy-overlap.cpp
deleted file mode 100644
index 36f1ec4da4f7..000000000000
--- a/compiler-rt/test/asan/TestCases/strcpy-overlap.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strcpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-
-// UNSUPPORTED: android
-
-#include <string.h>
-
-
-// Don't inline function otherwise stacktrace changes.
-__attribute__((noinline)) void bad_function() {
-  char buffer[] = "hello";
-  // CHECK: strcpy-param-overlap: memory ranges
-  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
-  // CHECK: {{#0 0x.* in .*strcpy}}
-  // CHECK: {{#1 0x.* in bad_function.*strcpy-overlap.cpp:}}[[@LINE+2]]
-  // CHECK: {{#2 0x.* in main .*strcpy-overlap.cpp:}}[[@LINE+5]]
-  strcpy(buffer, buffer + 1); // BOOM
-}
-
-int main(int argc, char **argv) {
-  bad_function();
-  return 0;
-}

diff  --git a/compiler-rt/test/asan/TestCases/strncat-overlap.cpp b/compiler-rt/test/asan/TestCases/strncat-overlap.cpp
deleted file mode 100644
index 9e6ad5914ef1..000000000000
--- a/compiler-rt/test/asan/TestCases/strncat-overlap.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncat" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-
-// UNSUPPORTED: android
-
-#include <string.h>
-
-
-// Don't inline function otherwise stacktrace changes.
-__attribute__((noinline)) void bad_function() {
-  char buffer[] = "hello\0XXX";
-  // CHECK: strncat-param-overlap: memory ranges
-  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
-  // CHECK: {{#0 0x.* in .*strncat}}
-  // CHECK: {{#1 0x.* in bad_function.*strncat-overlap.cpp:}}[[@LINE+2]]
-  // CHECK: {{#2 0x.* in main .*strncat-overlap.cpp:}}[[@LINE+5]]
-  strncat(buffer, buffer + 1, 3); // BOOM
-}
-
-int main(int argc, char **argv) {
-  bad_function();
-  return 0;
-}

diff  --git a/compiler-rt/test/asan/TestCases/strncpy-overlap.cpp b/compiler-rt/test/asan/TestCases/strncpy-overlap.cpp
deleted file mode 100644
index f855b6af3bb3..000000000000
--- a/compiler-rt/test/asan/TestCases/strncpy-overlap.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O1 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O2 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-//
-// RUN: %clangxx_asan -O3 %s -o %t
-// RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: echo "interceptor_via_fun:bad_function" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-// RUN: echo "interceptor_name:strncpy" > %t.supp
-// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t
-
-// UNSUPPORTED: android
-
-#include <string.h>
-
-
-// Don't inline function otherwise stacktrace changes.
-__attribute__((noinline)) void bad_function() {
-  char buffer[] = "hello";
-  // CHECK: strncpy-param-overlap: memory ranges
-  // CHECK: [{{0x.*,[ ]*0x.*}}) and [{{0x.*,[ ]*0x.*}}) overlap
-  // CHECK: {{#0 0x.* in .*strncpy}}
-  // CHECK: {{#1 0x.* in bad_function.*strncpy-overlap.cpp:}}[[@LINE+2]]
-  // CHECK: {{#2 0x.* in main .*strncpy-overlap.cpp:}}[[@LINE+5]]
-  strncpy(buffer, buffer + 1, 5); // BOOM
-}
-
-int main(int argc, char **argv) {
-  bad_function();
-  return 0;
-}

diff  --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 86e9b48826e3..bf63d7baea80 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -217,6 +217,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     LLVM_FALLTHROUGH;
   case LibFunc_stpcpy:
   case LibFunc_stpncpy:
+    Changed |= setOnlyAccessesArgMemory(F);
     Changed |= setDoesNotThrow(F);
     Changed |= setDoesNotCapture(F, 1);
     Changed |= setOnlyReadsMemory(F, 1);
@@ -251,6 +252,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     return Changed;
   case LibFunc_strstr:
   case LibFunc_strpbrk:
+    Changed |= setOnlyAccessesArgMemory(F);
     Changed |= setOnlyReadsMemory(F);
     Changed |= setDoesNotThrow(F);
     Changed |= setDoesNotCapture(F, 1);
@@ -446,6 +448,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     return Changed;
   case LibFunc_bcopy:
     Changed |= setDoesNotThrow(F);
+    Changed |= setOnlyAccessesArgMemory(F);
     Changed |= setDoesNotCapture(F, 0);
     Changed |= setDoesNotCapture(F, 1);
     Changed |= setOnlyReadsMemory(F, 0);
@@ -459,6 +462,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) {
     return Changed;
   case LibFunc_bzero:
     Changed |= setDoesNotThrow(F);
+    Changed |= setOnlyAccessesArgMemory(F);
     Changed |= setDoesNotCapture(F, 0);
     return Changed;
   case LibFunc_calloc:

diff  --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index c374e90cc075..a003eef6606f 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -247,10 +247,10 @@ declare i64 @atoll(i8*)
 ; CHECK-NVPTX-NOT: declare i32 @bcmp(i8* nocapture, i8* nocapture, i64) [[G2]]
 declare i32 @bcmp(i8*, i8*, i64)
 
-; CHECK: declare void @bcopy(i8* nocapture readonly, i8* nocapture, i64) [[G1]]
+; CHECK: declare void @bcopy(i8* nocapture readonly, i8* nocapture, i64)  [[ARGMEMONLY_NOFREE_NOUNWIND:#[0-9]+]]
 declare void @bcopy(i8*, i8*, i64)
 
-; CHECK: declare void @bzero(i8* nocapture, i64) [[G1]]
+; CHECK: declare void @bzero(i8* nocapture, i64)  [[ARGMEMONLY_NOFREE_NOUNWIND:#[0-9]+]]
 declare void @bzero(i8*, i64)
 
 ; CHECK: declare noalias noundef i8* @calloc(i64, i64) [[G1]]
@@ -451,7 +451,7 @@ declare i32 @fputs(i8*, %opaque*)
 ; CHECK: declare noundef i64 @fread(i8* nocapture noundef, i64 noundef, i64 noundef, %opaque* nocapture noundef) [[G1]]
 declare i64 @fread(i8*, i64, i64, %opaque*)
 
-; CHECK: declare void @free(i8* nocapture noundef) [[G3:#[0-9]+]]
+; CHECK: declare void @free(i8* nocapture noundef) [[NOUNWIND:#[0-9]+]]
 declare void @free(i8*)
 
 ; CHECK: declare double @frexp(double, i32* nocapture) [[G1]]
@@ -726,7 +726,7 @@ declare i64 @read(i32, i8*, i64)
 ; CHECK: declare noundef i64 @readlink(i8* nocapture noundef readonly, i8* nocapture noundef, i64 noundef) [[G1]]
 declare i64 @readlink(i8*, i8*, i64)
 
-; CHECK: declare noalias noundef i8* @realloc(i8* nocapture, i64) [[G3]]
+; CHECK: declare noalias noundef i8* @realloc(i8* nocapture, i64) [[NOUNWIND]]
 declare i8* @realloc(i8*, i64)
 
 ; CHECK: declare noundef i8* @reallocf(i8*, i64)
@@ -825,16 +825,16 @@ declare i32 @statvfs(i8*, %opaque*)
 ; CHECK-LINUX: declare noundef i32 @statvfs64(i8* nocapture noundef readonly, %opaque* nocapture noundef) [[G1]]
 declare i32 @statvfs64(i8*, %opaque*)
 
-; CHECK: declare i8* @stpcpy(i8* noalias, i8* noalias nocapture readonly) [[G1]]
+; CHECK: declare i8* @stpcpy(i8* noalias, i8* noalias nocapture readonly) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @stpcpy(i8*, i8*)
 
-; CHECK: declare i8* @stpncpy(i8* noalias, i8* noalias nocapture readonly, i64) [[G1]]
+; CHECK: declare i8* @stpncpy(i8* noalias, i8* noalias nocapture readonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @stpncpy(i8*, i8*, i64)
 
 ; CHECK: declare i32 @strcasecmp(i8* nocapture, i8* nocapture) [[G2]]
 declare i32 @strcasecmp(i8*, i8*)
 
-; CHECK: declare i8* @strcat(i8* noalias returned, i8* noalias nocapture readonly) [[G1]]
+; CHECK: declare i8* @strcat(i8* noalias returned, i8* noalias nocapture readonly) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @strcat(i8*, i8*)
 
 ; CHECK: declare i8* @strchr(i8*, i32) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]]
@@ -846,7 +846,7 @@ declare i32 @strcmp(i8*, i8*)
 ; CHECK: declare i32 @strcoll(i8* nocapture, i8* nocapture) [[G2]]
 declare i32 @strcoll(i8*, i8*)
 
-; CHECK: declare i8* @strcpy(i8* noalias returned, i8* noalias nocapture readonly) [[G1]]
+; CHECK: declare i8* @strcpy(i8* noalias returned, i8* noalias nocapture readonly) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @strcpy(i8*, i8*)
 
 ; CHECK: declare i64 @strcspn(i8* nocapture, i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]]
@@ -861,13 +861,13 @@ declare i64 @strlen(i8*)
 ; CHECK: declare i32 @strncasecmp(i8* nocapture, i8* nocapture, i64) [[G2]]
 declare i32 @strncasecmp(i8*, i8*, i64)
 
-; CHECK: declare i8* @strncat(i8* noalias returned, i8* noalias nocapture readonly, i64) [[G1]]
+; CHECK: declare i8* @strncat(i8* noalias returned, i8* noalias nocapture readonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @strncat(i8*, i8*, i64)
 
 ; CHECK: declare i32 @strncmp(i8* nocapture, i8* nocapture, i64) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]]
 declare i32 @strncmp(i8*, i8*, i64)
 
-; CHECK: declare i8* @strncpy(i8* noalias returned, i8* noalias nocapture readonly, i64) [[G1]]
+; CHECK: declare i8* @strncpy(i8* noalias returned, i8* noalias nocapture readonly, i64) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @strncpy(i8*, i8*, i64)
 
 ; CHECK: declare noalias i8* @strndup(i8* nocapture readonly, i64) [[G1]]
@@ -876,7 +876,7 @@ declare i8* @strndup(i8*, i64)
 ; CHECK: declare i64 @strnlen(i8*, i64) [[G0]]
 declare i64 @strnlen(i8*, i64)
 
-; CHECK: declare i8* @strpbrk(i8*, i8* nocapture) [[G2]]
+; CHECK: declare i8* @strpbrk(i8*, i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND:#[0-9]+]]
 declare i8* @strpbrk(i8*, i8*)
 
 ; CHECK: declare i8* @strrchr(i8*, i32) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]]
@@ -885,7 +885,7 @@ declare i8* @strrchr(i8*, i32)
 ; CHECK: declare i64 @strspn(i8* nocapture, i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]]
 declare i64 @strspn(i8*, i8*)
 
-; CHECK: declare i8* @strstr(i8*, i8* nocapture) [[G2]]
+; CHECK: declare i8* @strstr(i8*, i8* nocapture) [[ARGMEMONLY_NOFREE_NOUNWIND]]
 declare i8* @strstr(i8*, i8*)
 
 ; CHECK: declare double @strtod(i8* readonly, i8** nocapture) [[G1]]
@@ -1007,13 +1007,23 @@ declare i64 @write(i32, i8*, i64)
 
 
 ; memset_pattern16 isn't available everywhere.
-; CHECK-DARWIN: declare void @memset_pattern16(i8* nocapture, i8* nocapture readonly, i64) [[G6:#[0-9]+]]
+; CHECK-DARWIN: declare void @memset_pattern16(i8* nocapture, i8* nocapture readonly, i64) [[ARGMEMONLY_NOFREE:#[0-9]+]]
 declare void @memset_pattern16(i8*, i8*, i64)
 
 ; CHECK: attributes [[G0]] = { nofree }
 ; CHECK: attributes [[G1]] = { nofree nounwind }
-; CHECK-DAG: attributes [[G2]] = { nofree nounwind readonly }
-; CHECK-DAG: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly }
-; CHECK-DAG: attributes [[G3]] = { nounwind }
-; CHECK-DAG: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind }
-; CHECK-DARWIN: attributes [[G6]] = { argmemonly nofree }
+; CHECK: attributes [[G2]] = { nofree nounwind readonly }
+
+; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind }
+; CHECK-DAG-UNKNOWN: attributes [[NOUNWIND]] = { nounwind }
+; CHECK-DAG-UNKNOWN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly }
+
+; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly }
+; CHECK-DAG-LINUX: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind }
+; CHECK-DAG-LINUX: attributes [[NOUNWIND]] = { nounwind }
+
+; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND]] = { argmemonly nofree nounwind }
+; CHECK-DAG-DARWIN: attributes [[NOUNWIND]] = { nounwind }
+; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE_NOUNWIND_READONLY]] = { argmemonly nofree nounwind readonly }
+; CHECK-DAG-DARWIN: attributes [[ARGMEMONLY_NOFREE]] = { argmemonly nofree }
+


        


More information about the llvm-commits mailing list