diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -756,6 +756,9 @@ if (CodeGenOpts.IBTSeal) getModule().addModuleFlag(llvm::Module::Override, "ibt-seal", 1); + if (CodeGenOpts.FunctionReturnThunks) + getModule().addModuleFlag(llvm::Module::Override, "function_return_thunk_extern", 1); + // Add module metadata for return address signing (ignoring // non-leaf/all) and stack tagging. These are actually turned on by function // attributes, but we use module metadata to emit build attributes. This is diff --git a/clang/test/CodeGen/attr-function-return.c b/clang/test/CodeGen/attr-function-return.c --- a/clang/test/CodeGen/attr-function-return.c +++ b/clang/test/CodeGen/attr-function-return.c @@ -7,6 +7,15 @@ // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ // RUN: -Werror=ignored-attributes -mfunction-return=thunk-extern \ // RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-EXTERN +// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ +// RUN: -mfunction-return=thunk-extern -fprofile-arcs \ +// RUN: | FileCheck %s --check-prefix=CHECK-GCOV +// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ +// RUN: -mfunction-return=thunk-extern -fsanitize=address \ +// RUN: | FileCheck %s --check-prefix=CHECK-ASAN +// RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \ +// RUN: -mfunction-return=thunk-extern -fsanitize=thread \ +// RUN: | FileCheck %s --check-prefix=CHECK-TSAN #if !__has_attribute(function_return) #error "missing attribute support for function_return" @@ -92,6 +101,16 @@ // CHECK-EXTERN: @no_attrs() [[EXTERN]] void no_attrs(void) {} +// Test synthetic functions. +// CHECK-GCOV: @__llvm_gcov_writeout() unnamed_addr [[EXTERNGCOV:#[0-9]+]] +// CHECK-GCOV: @__llvm_gcov_reset() unnamed_addr [[EXTERNGCOV]] +// CHECK-GCOV: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]] +// CHECK-ASAN: @asan.module_ctor() [[EXTERNASAN:#[0-9]+]] +// CHECK-TSAN: @tsan.module_ctor() [[EXTERNTSAN:#[0-9]+]] + // CHECK-NOM-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern // CHECK-KEEP-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern // CHECK: [[EXTERN]] = {{.*}}fn_ret_thunk_extern +// CHECK-GCOV: [[EXTERNGCOV]] = {{.*}}fn_ret_thunk_extern +// CHECK-ASAN: [[EXTERNASAN]] = {{.*}}fn_ret_thunk_extern +// CHECK-TSAN: [[EXTERNTSAN]] = {{.*}}fn_ret_thunk_extern diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7364,6 +7364,8 @@ - "frame-pointer": **Max**. The value can be 0, 1, or 2. A synthesized function will get the "frame-pointer" function attribute, with value being "none", "non-leaf", or "all", respectively. +- "function_return_thunk_extern": The synthesized function will get the + ``fn_return_thunk_extern`` function attribute. - "uwtable": **Max**. The value can be 0, 1, or 2. If the value is 1, a synthesized function will get the ``uwtable(sync)`` function attribute, if the value is 2, a synthesized function will get the ``uwtable(async)`` function attribute. diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -354,6 +354,8 @@ B.addAttribute("frame-pointer", "all"); break; } + if (M->getModuleFlag("function_return_thunk_extern")) + B.addAttribute(Attribute::FnRetThunkExtern); F->addFnAttrs(B); return F; }