[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-19 Thread serge via Phabricator via cfe-commits
serge-sans-paille added a comment.

https://reviews.llvm.org/D112059 should address the issue pointed by 
@manojgupta and @nickdesaulniers


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-18 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

Also reported here: 
https://lore.kernel.org/llvm/1817774243.12566.1634255267713@localhost/


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-18 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

See also: https://github.com/ClangBuiltLinux/linux/issues/1477.  Surprising 
that this didn't show up in newer kernels, just older (but still supported) 
kernel versions. Sorry I missed that in my tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-16 Thread Manoj Gupta via Phabricator via cfe-commits
manojgupta added a comment.

I am noticing a clang crash with ToT after this change.

- testcase --

  long a;
  char b, d;
  extern inline __attribute__((always_inline))
  __attribute__((gnu_inline)) unsigned long
  strlen() {
return a;
  }
  c(void) {
strlen();
return 0;
  }
  unsigned long strlen() { return d; }

  bin/clang -x c foo.c -Wno-error
  foo.c:8:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
  c(void) {
  ^
  Global is external, but doesn't have external or weak linkage!
  i64 (i8*)* @strlen.inline
  fatal error: error in backend: Broken module found, compilation aborted!
  clang version 14.0.0 (https://github.com/llvm/llvm-project.git 
3129aa5caf1f9b5c48ab708f43cb3fc5173dd021)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-04 Thread serge via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG0f0e31cf511d: Update inline builtin handling to honor gnu 
inline attribute (authored by serge-sans-paille).

Changed prior to commit:
  https://reviews.llvm.org/D111009?vs=376812=377023#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/test/CodeGen/memcmp-inline-builtin-to-asm.c
  clang/test/CodeGen/memcpy-inline-builtin-no-extern.c
  clang/test/CodeGen/memcpy-inline-builtin.c
  clang/test/CodeGen/memcpy-nobuiltin.c
  clang/test/CodeGen/memcpy-nobuiltin.inc
  clang/test/CodeGen/pr9614.c

Index: clang/test/CodeGen/pr9614.c
===
--- clang/test/CodeGen/pr9614.c
+++ clang/test/CodeGen/pr9614.c
@@ -32,14 +32,14 @@
 
 // CHECK-LABEL: define{{.*}} void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 %0)
+// CHECK: call i32 @abs(i32 0)
 // CHECK: call i8* @strrchr(
 // CHECK: call void @llvm.prefetch.p0i8(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 
 // CHECK: declare void @foo()
+// CHECK: declare i32 @abs(i32
 // CHECK: declare i8* @strrchr(i8*, i32)
 // CHECK: declare i8* @memchr(
-// CHECK: declare i32 @abs(i32
 // CHECK: declare void @llvm.prefetch.p0i8(
Index: clang/test/CodeGen/memcpy-nobuiltin.inc
===
--- clang/test/CodeGen/memcpy-nobuiltin.inc
+++ clang/test/CodeGen/memcpy-nobuiltin.inc
@@ -2,7 +2,7 @@
 extern void *memcpy(void *dest, void const *from, size_t n);
 
 #ifdef WITH_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   char const *ifrom = from;
   char *idest = dest;
   while (n--)
@@ -11,7 +11,7 @@
 }
 #endif
 #ifdef WITH_SELF_REFERENCE_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   if (n != 0)
 memcpy(dest, from, n);
   return dest;
Index: clang/test/CodeGen/memcpy-nobuiltin.c
===
--- clang/test/CodeGen/memcpy-nobuiltin.c
+++ clang/test/CodeGen/memcpy-nobuiltin.c
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_DECL | FileCheck --check-prefix=CHECK-WITH-DECL %s
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -UWITH_DECL | FileCheck --check-prefix=CHECK-NO-DECL %s
-// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
+// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -disable-llvm-passes -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
 //
 // CHECK-WITH-DECL-NOT: @llvm.memcpy
 // CHECK-NO-DECL: @llvm.memcpy
 // CHECK-SELF-REF-DECL-LABEL: define {{.*}}i8* @memcpy.inline
-// CHECK-SELF-REF-DECL:   @memcpy(
+// CHECK-SELF-REF-DECL:   @llvm.memcpy.{{.*}}(
 //
 #include 
 void test(void *dest, void const *from, size_t n) {
Index: clang/test/CodeGen/memcpy-inline-builtin.c
===
--- clang/test/CodeGen/memcpy-inline-builtin.c
+++ clang/test/CodeGen/memcpy-inline-builtin.c
@@ -32,13 +32,39 @@
 // CHECK-NEXT:store i8* [[TMP0]], i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:store i8* [[TMP1]], i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:store i64 [[TMP2]], i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR2:[0-9]+]], !srcloc !2
+// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR4:[0-9]+]], !srcloc !2
 // CHECK-NEXT:[[TMP3:%.*]] = load i8*, i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP4:%.*]] = load i8*, i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP5:%.*]] = load i64, i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR2]]
+// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR4]]
+// CHECK-NEXT:ret i8* [[TMP3]]
+//
+void *foo(void *a, const void *b, size_t c) {
+  return memcpy(a, b, c);
+}
+
+// CHECK-LABEL: @bar(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[B_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[C_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[CPY:%.*]] = alloca i8* (i8*, i8*, i64)*, align 8

[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-04 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers accepted this revision.
nickdesaulniers added inline comments.
This revision is now accepted and ready to land.



Comment at: clang/lib/CodeGen/CGExpr.cpp:4901
+  llvm::Function *Fn = llvm::cast(CalleePtr);
+  llvm::Module  = CGF.CGM.getModule();
+  llvm::Function *Clone = M.getFunction(FDInlineName);

llvm::Module *M = Fn->getParent();


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-04 Thread serge via Phabricator via cfe-commits
serge-sans-paille updated this revision to Diff 376812.
serge-sans-paille added a comment.

+ extra test case
+ use internal linkage instead of available_externally linkage for generated 
clone


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/test/CodeGen/memcmp-inline-builtin-to-asm.c
  clang/test/CodeGen/memcpy-inline-builtin-no-extern.c
  clang/test/CodeGen/memcpy-inline-builtin.c
  clang/test/CodeGen/memcpy-nobuiltin.c
  clang/test/CodeGen/memcpy-nobuiltin.inc
  clang/test/CodeGen/pr9614.c

Index: clang/test/CodeGen/pr9614.c
===
--- clang/test/CodeGen/pr9614.c
+++ clang/test/CodeGen/pr9614.c
@@ -32,14 +32,14 @@
 
 // CHECK-LABEL: define{{.*}} void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 %0)
+// CHECK: call i32 @abs(i32 0)
 // CHECK: call i8* @strrchr(
 // CHECK: call void @llvm.prefetch.p0i8(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 
 // CHECK: declare void @foo()
+// CHECK: declare i32 @abs(i32
 // CHECK: declare i8* @strrchr(i8*, i32)
 // CHECK: declare i8* @memchr(
-// CHECK: declare i32 @abs(i32
 // CHECK: declare void @llvm.prefetch.p0i8(
Index: clang/test/CodeGen/memcpy-nobuiltin.inc
===
--- clang/test/CodeGen/memcpy-nobuiltin.inc
+++ clang/test/CodeGen/memcpy-nobuiltin.inc
@@ -2,7 +2,7 @@
 extern void *memcpy(void *dest, void const *from, size_t n);
 
 #ifdef WITH_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   char const *ifrom = from;
   char *idest = dest;
   while (n--)
@@ -11,7 +11,7 @@
 }
 #endif
 #ifdef WITH_SELF_REFERENCE_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   if (n != 0)
 memcpy(dest, from, n);
   return dest;
Index: clang/test/CodeGen/memcpy-nobuiltin.c
===
--- clang/test/CodeGen/memcpy-nobuiltin.c
+++ clang/test/CodeGen/memcpy-nobuiltin.c
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_DECL | FileCheck --check-prefix=CHECK-WITH-DECL %s
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -UWITH_DECL | FileCheck --check-prefix=CHECK-NO-DECL %s
-// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
+// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -disable-llvm-passes -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
 //
 // CHECK-WITH-DECL-NOT: @llvm.memcpy
 // CHECK-NO-DECL: @llvm.memcpy
 // CHECK-SELF-REF-DECL-LABEL: define {{.*}}i8* @memcpy.inline
-// CHECK-SELF-REF-DECL:   @memcpy(
+// CHECK-SELF-REF-DECL:   @llvm.memcpy.{{.*}}(
 //
 #include 
 void test(void *dest, void const *from, size_t n) {
Index: clang/test/CodeGen/memcpy-inline-builtin.c
===
--- clang/test/CodeGen/memcpy-inline-builtin.c
+++ clang/test/CodeGen/memcpy-inline-builtin.c
@@ -32,13 +32,39 @@
 // CHECK-NEXT:store i8* [[TMP0]], i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:store i8* [[TMP1]], i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:store i64 [[TMP2]], i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR2:[0-9]+]], !srcloc !2
+// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR4:[0-9]+]], !srcloc !2
 // CHECK-NEXT:[[TMP3:%.*]] = load i8*, i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP4:%.*]] = load i8*, i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP5:%.*]] = load i64, i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR2]]
+// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR4]]
+// CHECK-NEXT:ret i8* [[TMP3]]
+//
+void *foo(void *a, const void *b, size_t c) {
+  return memcpy(a, b, c);
+}
+
+// CHECK-LABEL: @bar(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[B_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[C_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[CPY:%.*]] = alloca i8* (i8*, i8*, i64)*, align 8
+// CHECK-NEXT:store i8* [[A:%.*]], i8** [[A_ADDR]], align 8
+// CHECK-NEXT:store i8* [[B:%.*]], i8** [[B_ADDR]], align 

[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

Diff 376794 builds! Let's still add a test for

  inline __attribute__((__always_inline__)) __attribute__((gnu_inline)) void*
  memcpy() {}

though.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

With Diff 376790

  inline __attribute__((__always_inline__)) __attribute__((gnu_inline)) void*
  memcpy() {}

`clang -O2` is producing undefined references to `memcpy.inline`. Please add 
that to the new unit tests added here.

  diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
  index a8ae5f5fc0de..132834516473 100644
  --- a/clang/lib/CodeGen/CodeGenFunction.cpp
  +++ b/clang/lib/CodeGen/CodeGenFunction.cpp
  @@ -1303,7 +1303,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, 
llvm::Function *Fn,
   llvm::Module *M = Fn->getParent();
   llvm::Function *Clone = M->getFunction(FDInlineName);
   if (!Clone) {
  -  Clone = llvm::Function::Create(Fn->getFunctionType(), Fn->getLinkage(),
  +  Clone = llvm::Function::Create(Fn->getFunctionType(), 
llvm::GlobalValue::AvailableExternallyLinkage,
Fn->getAddressSpace(), FDInlineName, M);
 Clone->addFnAttr(llvm::Attribute::AlwaysInline);
   }

fixes that, but I don't think that's the right visibility.

  02a0 T memcpy.inline

should be `t` not `T` I think?  Because now the failure looks like

  ld.lld: error: duplicate symbol: memcpy.inline
  >>> defined at file.c
  >>>fs/efivarfs/file.o:(memcpy.inline)
  >>> defined at super.c
  >>>fs/efivarfs/super.o:(.text+0x800)

Perhaps `llvm::GlobalValue::InternalLinkage`?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread serge via Phabricator via cfe-commits
serge-sans-paille updated this revision to Diff 376794.
serge-sans-paille added a comment.

+ fix linkage of generated function


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/test/CodeGen/memcmp-inline-builtin-to-asm.c
  clang/test/CodeGen/memcpy-inline-builtin.c
  clang/test/CodeGen/memcpy-nobuiltin.c
  clang/test/CodeGen/memcpy-nobuiltin.inc
  clang/test/CodeGen/pr9614.c

Index: clang/test/CodeGen/pr9614.c
===
--- clang/test/CodeGen/pr9614.c
+++ clang/test/CodeGen/pr9614.c
@@ -32,14 +32,14 @@
 
 // CHECK-LABEL: define{{.*}} void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 %0)
+// CHECK: call i32 @abs(i32 0)
 // CHECK: call i8* @strrchr(
 // CHECK: call void @llvm.prefetch.p0i8(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 
 // CHECK: declare void @foo()
+// CHECK: declare i32 @abs(i32
 // CHECK: declare i8* @strrchr(i8*, i32)
 // CHECK: declare i8* @memchr(
-// CHECK: declare i32 @abs(i32
 // CHECK: declare void @llvm.prefetch.p0i8(
Index: clang/test/CodeGen/memcpy-nobuiltin.inc
===
--- clang/test/CodeGen/memcpy-nobuiltin.inc
+++ clang/test/CodeGen/memcpy-nobuiltin.inc
@@ -2,7 +2,7 @@
 extern void *memcpy(void *dest, void const *from, size_t n);
 
 #ifdef WITH_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   char const *ifrom = from;
   char *idest = dest;
   while (n--)
@@ -11,7 +11,7 @@
 }
 #endif
 #ifdef WITH_SELF_REFERENCE_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   if (n != 0)
 memcpy(dest, from, n);
   return dest;
Index: clang/test/CodeGen/memcpy-nobuiltin.c
===
--- clang/test/CodeGen/memcpy-nobuiltin.c
+++ clang/test/CodeGen/memcpy-nobuiltin.c
@@ -1,11 +1,11 @@
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_DECL | FileCheck --check-prefix=CHECK-WITH-DECL %s
 // RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -UWITH_DECL | FileCheck --check-prefix=CHECK-NO-DECL %s
-// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
+// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -disable-llvm-passes -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s
 //
 // CHECK-WITH-DECL-NOT: @llvm.memcpy
 // CHECK-NO-DECL: @llvm.memcpy
 // CHECK-SELF-REF-DECL-LABEL: define {{.*}}i8* @memcpy.inline
-// CHECK-SELF-REF-DECL:   @memcpy(
+// CHECK-SELF-REF-DECL:   @llvm.memcpy.{{.*}}(
 //
 #include 
 void test(void *dest, void const *from, size_t n) {
Index: clang/test/CodeGen/memcpy-inline-builtin.c
===
--- clang/test/CodeGen/memcpy-inline-builtin.c
+++ clang/test/CodeGen/memcpy-inline-builtin.c
@@ -32,13 +32,39 @@
 // CHECK-NEXT:store i8* [[TMP0]], i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:store i8* [[TMP1]], i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:store i64 [[TMP2]], i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR2:[0-9]+]], !srcloc !2
+// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR4:[0-9]+]], !srcloc !2
 // CHECK-NEXT:[[TMP3:%.*]] = load i8*, i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP4:%.*]] = load i8*, i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP5:%.*]] = load i64, i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR2]]
+// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR4]]
+// CHECK-NEXT:ret i8* [[TMP3]]
+//
+void *foo(void *a, const void *b, size_t c) {
+  return memcpy(a, b, c);
+}
+
+// CHECK-LABEL: @bar(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[B_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[C_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[CPY:%.*]] = alloca i8* (i8*, i8*, i64)*, align 8
+// CHECK-NEXT:store i8* [[A:%.*]], i8** [[A_ADDR]], align 8
+// CHECK-NEXT:store i8* [[B:%.*]], i8** [[B_ADDR]], align 8
+// CHECK-NEXT:store i64 [[C:%.*]], i64* [[C_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load i64, i64* 

[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

With Diff 376790, I'm seeing a similar failure to 
https://github.com/ClangBuiltLinux/linux/issues/1466#issue-1011472964, but from 
different TUs.

  ld.lld: error: duplicate symbol: memcpy.inline
  >>> defined at file.c
  >>>fs/efivarfs/file.o:(memcpy.inline)
  >>> defined at super.c
  >>>fs/efivarfs/super.o:(.text+0x800)

let me see if I can put together another reproducer.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread serge via Phabricator via cfe-commits
serge-sans-paille updated this revision to Diff 376790.
serge-sans-paille added a comment.

+ extra test case
+ avoid Playing with Twines
+ fix storage of external declaration of inline builtins
+ minor nits


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/test/CodeGen/memcmp-inline-builtin-to-asm.c
  clang/test/CodeGen/memcpy-inline-builtin.c
  clang/test/CodeGen/memcpy-nobuiltin.c
  clang/test/CodeGen/memcpy-nobuiltin.inc
  clang/test/CodeGen/pr9614.c

Index: clang/test/CodeGen/pr9614.c
===
--- clang/test/CodeGen/pr9614.c
+++ clang/test/CodeGen/pr9614.c
@@ -32,14 +32,14 @@
 
 // CHECK-LABEL: define{{.*}} void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 %0)
+// CHECK: call i32 @abs(i32 0)
 // CHECK: call i8* @strrchr(
 // CHECK: call void @llvm.prefetch.p0i8(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 
 // CHECK: declare void @foo()
+// CHECK: declare i32 @abs(i32
 // CHECK: declare i8* @strrchr(i8*, i32)
 // CHECK: declare i8* @memchr(
-// CHECK: declare i32 @abs(i32
 // CHECK: declare void @llvm.prefetch.p0i8(
Index: clang/test/CodeGen/memcpy-nobuiltin.inc
===
--- clang/test/CodeGen/memcpy-nobuiltin.inc
+++ clang/test/CodeGen/memcpy-nobuiltin.inc
@@ -2,7 +2,7 @@
 extern void *memcpy(void *dest, void const *from, size_t n);
 
 #ifdef WITH_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   char const *ifrom = from;
   char *idest = dest;
   while (n--)
@@ -11,7 +11,7 @@
 }
 #endif
 #ifdef WITH_SELF_REFERENCE_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   if (n != 0)
 memcpy(dest, from, n);
   return dest;
Index: clang/test/CodeGen/memcpy-nobuiltin.c
===
--- clang/test/CodeGen/memcpy-nobuiltin.c
+++ clang/test/CodeGen/memcpy-nobuiltin.c
@@ -5,7 +5,7 @@
 // CHECK-WITH-DECL-NOT: @llvm.memcpy
 // CHECK-NO-DECL: @llvm.memcpy
 // CHECK-SELF-REF-DECL-LABEL: define {{.*}}i8* @memcpy.inline
-// CHECK-SELF-REF-DECL:   @memcpy(
+// CHECK-SELF-REF-DECL:   @llvm.memcpy.{{.*}}(
 //
 #include 
 void test(void *dest, void const *from, size_t n) {
Index: clang/test/CodeGen/memcpy-inline-builtin.c
===
--- clang/test/CodeGen/memcpy-inline-builtin.c
+++ clang/test/CodeGen/memcpy-inline-builtin.c
@@ -32,13 +32,39 @@
 // CHECK-NEXT:store i8* [[TMP0]], i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:store i8* [[TMP1]], i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:store i64 [[TMP2]], i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR2:[0-9]+]], !srcloc !2
+// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR4:[0-9]+]], !srcloc !2
 // CHECK-NEXT:[[TMP3:%.*]] = load i8*, i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP4:%.*]] = load i8*, i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP5:%.*]] = load i64, i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR2]]
+// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR4]]
+// CHECK-NEXT:ret i8* [[TMP3]]
+//
+void *foo(void *a, const void *b, size_t c) {
+  return memcpy(a, b, c);
+}
+
+// CHECK-LABEL: @bar(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[B_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[C_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[CPY:%.*]] = alloca i8* (i8*, i8*, i64)*, align 8
+// CHECK-NEXT:store i8* [[A:%.*]], i8** [[A_ADDR]], align 8
+// CHECK-NEXT:store i8* [[B:%.*]], i8** [[B_ADDR]], align 8
+// CHECK-NEXT:store i64 [[C:%.*]], i64* [[C_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load i64, i64* [[C_ADDR]], align 8
+// CHECK-NEXT:[[CMP:%.*]] = icmp ugt i64 [[TMP0]], 10
+// CHECK-NEXT:[[TMP1:%.*]] = zext i1 [[CMP]] to i64
+// CHECK-NEXT:[[COND:%.*]] = select i1 [[CMP]], i8* (i8*, i8*, i64)* @memcpy, i8* (i8*, i8*, i64)* @foo
+// CHECK-NEXT:store i8* (i8*, i8*, i64)* [[COND]], i8* (i8*, i8*, i64)** [[CPY]], align 8
+// CHECK-NEXT:[[TMP2:%.*]] = load i8* (i8*, i8*, i64)*, i8* (i8*, i8*, i64)** [[CPY]], align 8
+// CHECK-NEXT:

[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

Here's a reduced test case from the kernel. Let's add a unit test for it.

  const void *con_unify_unimap_p1;
  extern inline __attribute__((__always_inline__)) __attribute__((gnu_inline))
  int memcmp(const void *p, const void *q, unsigned long size) {
__builtin_memcmp(p, q, size);
  }
  void con_unify_unimap_q1(void) {
memcmp(con_unify_unimap_p1, con_unify_unimap_q1, sizeof(int));
  }


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added inline comments.



Comment at: clang/lib/CodeGen/CGExpr.cpp:4911
+  if (!Clone) {
+Clone = llvm::Function::Create(Fn->getFunctionType(), Fn->getLinkage(),
+   Fn->getAddressSpace(),

given the reported ICE, I wonder if we shouldn't be reusing the `Fn`'s linkage, 
but explicitly setting extern? Same with below.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

Note: kernel tests need to have `CONFIG_FORTIFY_SOURCE=y` enabled in the config 
to use the fortified routines; this isn't enabled by default in an x86_64 
`defconfig` build.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111009/new/

https://reviews.llvm.org/D111009

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread Nick Desaulniers via Phabricator via cfe-commits
nickdesaulniers added a comment.

hmm...this seems to cause a bunch of ICEs building the kernel:

  Global is external, but doesn't have external or weak linkage!
  i64 (i8*)* @strlen
  fatal error: error in backend: Broken module found, compilation aborted!
  Global is external, but doesn't have external or weak linkage!
  i8* (i8*, i8*, i64)* @strncpy
  Global is external, but doesn't have external or weak linkage!
  i8* (i8*, i8*)* @strcpy
  Global is external, but doesn't have external or weak linkage!
  i64 (i8*)* @strlen
  Global is external, but doesn't have external or weak linkage!
  i64 (i8*, i8*, i64)* @strlcpy
  Global is external, but doesn't have external or weak linkage!
  i8* (i8*, i32, i64)* @memchr




Comment at: clang/lib/CodeGen/CGExpr.cpp:4895
+
+// Replaceable builtin provide their own implementation of a builtin. If we
+// are in an inline builtin implementation, avoid trivial infinite

s/Replaceable builtin/Replaceable builtins/



Comment at: clang/lib/CodeGen/CGExpr.cpp:4898
 // recursion.
+StringRef FDInlineName = (FD->getName() + ".inline").str();
 if (!FD->isInlineBuiltinDeclaration() ||

When building this patch (with Clang, via cmake vars `-DCMAKE_C_COMPILER=` and 
`-DCMAKE_CXX_COMPILER=`), I observe the following warning:

```
[99/110] Building CXX object 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGExpr.cpp.o
/android0/llvm-project/clang/lib/CodeGen/CGExpr.cpp:4898:30: warning: object 
backing the pointer will be destroyed at the end of the full-expression 
[-Wdangling-gsl]
StringRef FDInlineName = (FD->getName() + ".inline").str();
 ^
```

This leads to crashes when using the resulting image built with assertions 
enabled.

```
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index afed918c5c7f..cb6469d58b4c 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4895,9 +4895,9 @@ static CGCallee EmitDirectCallee(CodeGenFunction , 
GlobalDecl GD) {
 // Replaceable builtin provide their own implementation of a builtin. If we
 // are in an inline builtin implementation, avoid trivial infinite
 // recursion.
-StringRef FDInlineName = (FD->getName() + ".inline").str();
+Twine FDInlineName = FD->getName() + ".inline";
 if (!FD->isInlineBuiltinDeclaration() ||
-CGF.CurFn->getName() == FDInlineName) {
+CGF.CurFn->getName() == FDInlineName.str()) {
   return CGCallee::forBuiltin(builtinID, FD);
 }
 // When directing calling an inline builtin, call it through it's mangled
@@ -4906,7 +4906,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction , 
GlobalDecl GD) {
   llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
   llvm::Function *Fn = llvm::cast(CalleePtr);
   llvm::Module  = CGF.CGM.getModule();
-  llvm::Function *Clone = M.getFunction(FDInlineName);
+  llvm::Function *Clone = M.getFunction(FDInlineName.str());
   if (!Clone) {
 Clone = llvm::Function::Create(Fn->getFunctionType(), Fn->getLinkage(),
Fn->getAddressSpace(),
```



Comment at: clang/lib/CodeGen/CGExpr.cpp:4901
+CGF.CurFn->getName() == FDInlineName) {
   return CGCallee::forBuiltin(builtinID, FD);
+}

I think if you flip the order of the branches by inverting the logic in the 
conditional, then you could avoid needing braces for the single statement 
branch. ie.

```
if (FD->isInlineBuiltinDeclaration() && CGF.CurFn->getName() != FDInlineName) {
  llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
  ...
} else
  return CGCallee::forBuiltin(builtinID, FD);
```



Comment at: clang/lib/CodeGen/CGExpr.cpp:4908
+  llvm::Function *Fn = llvm::cast(CalleePtr);
+  llvm::Module  = CGF.CGM.getModule();
+  llvm::Function *Clone = M.getFunction(FDInlineName);

If you have a handle to a `Function`, you can get a pointer to it's module via 
`Function::getParent()`.



Comment at: clang/lib/CodeGen/CGExpr.cpp:4913
+   Fn->getAddressSpace(),
+   FD->getName() + ".inline", );
+Clone->addFnAttr(llvm::Attribute::AlwaysInline);

Can we reuse `FDInlineName` here for the 4th param?



Comment at: clang/lib/CodeGen/CodeGenFunction.cpp:1302
+  if (FD->isInlineBuiltinDeclaration() && Fn) {
+llvm::Module  = CGM.getModule();
+llvm::Function *Clone = M.getFunction((Fn->getName() + ".inline").str());

could use `Fn->getParent()` here, too.



Comment at: clang/lib/CodeGen/CodeGenFunction.cpp:1307
+ Fn->getAddressSpace(),
+ (Fn->getName() + ".inline").str(), 

[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute

2021-10-03 Thread serge via Phabricator via cfe-commits
serge-sans-paille created this revision.
serge-sans-paille added reviewers: kees, nickdesaulniers.
serge-sans-paille requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Per the GCC info page:

  If the function is declared 'extern', then this definition of the
  function is used only for inlining.  In no case is the function
  compiled as a standalone function, not even if you take its address
  explicitly.  Such an address becomes an external reference, as if
  you had only declared the function, and had not defined it.

Respect that behavior for inline builtins: keep the original definition, and
generate a copy of the declaration suffixed by '.inline' that's only referenced
in direct call.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D111009

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/test/CodeGen/memcpy-inline-builtin.c
  clang/test/CodeGen/memcpy-nobuiltin.c
  clang/test/CodeGen/memcpy-nobuiltin.inc
  clang/test/CodeGen/pr9614.c

Index: clang/test/CodeGen/pr9614.c
===
--- clang/test/CodeGen/pr9614.c
+++ clang/test/CodeGen/pr9614.c
@@ -32,14 +32,14 @@
 
 // CHECK-LABEL: define{{.*}} void @f()
 // CHECK: call void @foo()
-// CHECK: call i32 @abs(i32 %0)
+// CHECK: call i32 @abs(i32 0)
 // CHECK: call i8* @strrchr(
 // CHECK: call void @llvm.prefetch.p0i8(
 // CHECK: call i8* @memchr(
 // CHECK: ret void
 
 // CHECK: declare void @foo()
+// CHECK: declare i32 @abs(i32
 // CHECK: declare i8* @strrchr(i8*, i32)
 // CHECK: declare i8* @memchr(
-// CHECK: declare i32 @abs(i32
 // CHECK: declare void @llvm.prefetch.p0i8(
Index: clang/test/CodeGen/memcpy-nobuiltin.inc
===
--- clang/test/CodeGen/memcpy-nobuiltin.inc
+++ clang/test/CodeGen/memcpy-nobuiltin.inc
@@ -2,7 +2,7 @@
 extern void *memcpy(void *dest, void const *from, size_t n);
 
 #ifdef WITH_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   char const *ifrom = from;
   char *idest = dest;
   while (n--)
@@ -11,7 +11,7 @@
 }
 #endif
 #ifdef WITH_SELF_REFERENCE_DECL
-inline __attribute__((always_inline)) void *memcpy(void *dest, void const *from, size_t n) {
+inline __attribute__((always_inline)) __attribute__((gnu_inline)) void *memcpy(void *dest, void const *from, size_t n) {
   if (n != 0)
 memcpy(dest, from, n);
   return dest;
Index: clang/test/CodeGen/memcpy-nobuiltin.c
===
--- clang/test/CodeGen/memcpy-nobuiltin.c
+++ clang/test/CodeGen/memcpy-nobuiltin.c
@@ -5,7 +5,7 @@
 // CHECK-WITH-DECL-NOT: @llvm.memcpy
 // CHECK-NO-DECL: @llvm.memcpy
 // CHECK-SELF-REF-DECL-LABEL: define {{.*}}i8* @memcpy.inline
-// CHECK-SELF-REF-DECL:   @memcpy(
+// CHECK-SELF-REF-DECL:   @llvm.memcpy.{{.*}}(
 //
 #include 
 void test(void *dest, void const *from, size_t n) {
Index: clang/test/CodeGen/memcpy-inline-builtin.c
===
--- clang/test/CodeGen/memcpy-inline-builtin.c
+++ clang/test/CodeGen/memcpy-inline-builtin.c
@@ -32,13 +32,39 @@
 // CHECK-NEXT:store i8* [[TMP0]], i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:store i8* [[TMP1]], i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:store i64 [[TMP2]], i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR2:[0-9]+]], !srcloc !2
+// CHECK-NEXT:call void asm sideeffect "# memcpy.inline marker", "~{dirflag},~{fpsr},~{flags}"() #[[ATTR4:[0-9]+]], !srcloc !2
 // CHECK-NEXT:[[TMP3:%.*]] = load i8*, i8** [[A_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP4:%.*]] = load i8*, i8** [[B_ADDR_I]], align 8
 // CHECK-NEXT:[[TMP5:%.*]] = load i64, i64* [[C_ADDR_I]], align 8
-// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR2]]
+// CHECK-NEXT:call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 [[TMP3]], i8* align 1 [[TMP4]], i64 [[TMP5]], i1 false) #[[ATTR4]]
+// CHECK-NEXT:ret i8* [[TMP3]]
+//
+void *foo(void *a, const void *b, size_t c) {
+  return memcpy(a, b, c);
+}
+
+// CHECK-LABEL: @bar(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[A_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[B_ADDR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT:[[C_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:[[CPY:%.*]] = alloca i8* (i8*, i8*, i64)*, align 8
+// CHECK-NEXT:store i8* [[A:%.*]], i8** [[A_ADDR]], align 8
+// CHECK-NEXT:store i8* [[B:%.*]], i8** [[B_ADDR]], align 8
+// CHECK-NEXT:store i64 [[C:%.*]], i64* [[C_ADDR]], align 8
+// CHECK-NEXT:[[TMP0:%.*]] = load i64,