[PATCH] D111009: Update inline builtin handling to honor gnu inline attribute
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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,