https://github.com/alanzhao1 created https://github.com/llvm/llvm-project/pull/133511
Certain functions require the `returns_twice` attribute in order to produce correct codegen. However, `-fno-builtin` removes all knowledge of functions that require this attribute, so this PR modifies Clang to add the `returns_twice` attribute even if `-fno-builtin` is set. This behavior is also consistent with what GCC does. It's not (easily) possible to get the builtin information from `Builtins.td` because `-fno-builtin` causes Clang to never initialize any builtins, so functions never get tokenized as functions/builtins that require `returns_twice`. Therefore, the most straightforward solution is to explicitly hard code the function names that require `returns_twice`. Fixes #122840 >From f4f5d88d287600c40746f16c008ed95d6838f9ff Mon Sep 17 00:00:00 2001 From: Alan Zhao <ayz...@google.com> Date: Fri, 28 Mar 2025 12:53:15 -0700 Subject: [PATCH] [clang] Automatically add the `returns_twice` attribute to certain functions even if `-fno-builtin` is set Certain functions require the `returns_twice` attribute in order to produce correct codegen. However, `-fno-builtin` removes all knowledge of functions that require this attribute, so this PR modifies Clang to add the `returns_twice` attribute even if `-fno-builtin` is set. This behavior is also consistent with what GCC does. It's not (easily) possible to get the builtin information from `Builtins.td` because `-fno-builtin` causes Clang to never initialize any builtins, so functions never get tokenized as functions/builtins that require `returns_twice`. Therefore, the most straightforward solution is to explicitly hard code the function names that require `returns_twice`. Fixes #122840 --- clang/lib/CodeGen/CGCall.cpp | 9 +++++++++ clang/test/CodeGen/2003-08-20-vfork-bug.c | 5 ++++- clang/test/CodeGen/setjmp.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 7aa77e55dbfcc..76119617f22e6 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2607,6 +2607,15 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, if (shouldDisableTailCalls()) FuncAttrs.addAttribute("disable-tail-calls", "true"); + // These functions require the returns_twice attribute for correct codegen, + // but the attribute may not be added if -fno-builtin is specified. We + // explicitly add that attribute here. + static const llvm::StringSet<> ReturnsTwiceFn{ + "_setjmpex", "setjmp", "_setjmp", "vfork", + "sigsetjmp", "__sigsetjmp", "savectx", "getcontext"}; + if (ReturnsTwiceFn.contains(Name)) + FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice); + // CPU/feature overrides. addDefaultFunctionDefinitionAttributes // handles these separately to set them based on the global defaults. GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs); diff --git a/clang/test/CodeGen/2003-08-20-vfork-bug.c b/clang/test/CodeGen/2003-08-20-vfork-bug.c index 4966ab20904d4..438604f321da3 100644 --- a/clang/test/CodeGen/2003-08-20-vfork-bug.c +++ b/clang/test/CodeGen/2003-08-20-vfork-bug.c @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -emit-llvm %s -o /dev/null +// RUN: %clang_cc1 -x c %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c %s -triple x86_64-linux-gnu -emit-llvm -fno-builtin -o - | FileCheck %s +// CHECK: ; Function Attrs: returns_twice +// CHECK-NEXT: declare {{.*}} @vfork( extern int vfork(void); void test() { vfork(); diff --git a/clang/test/CodeGen/setjmp.c b/clang/test/CodeGen/setjmp.c index 77dde35e69cae..00341e459941a 100644 --- a/clang/test/CodeGen/setjmp.c +++ b/clang/test/CodeGen/setjmp.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -x c %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c %s -triple x86_64-linux-gnu -emit-llvm -fno-builtin -o - | FileCheck %s // RUN: %clang_cc1 -x c++ %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s #ifdef __cplusplus @@ -6,13 +7,17 @@ extern "C" { #endif struct __jmp_buf_tag { int n; }; +struct __ucontext_t_tag { int n; }; int setjmp(struct __jmp_buf_tag*); int sigsetjmp(struct __jmp_buf_tag*, int); int _setjmp(struct __jmp_buf_tag*); int __sigsetjmp(struct __jmp_buf_tag*, int); +int _setjmpex(struct __jmp_buf_tag* env); +int getcontext(struct __ucontext_t_tag*); typedef struct __jmp_buf_tag jmp_buf[1]; typedef struct __jmp_buf_tag sigjmp_buf[1]; +typedef struct __ucontext_t_tag ucontext_t[1]; #ifdef __cplusplus } @@ -20,6 +25,7 @@ typedef struct __jmp_buf_tag sigjmp_buf[1]; void f(void) { jmp_buf jb; + ucontext_t ut; // CHECK: call {{.*}}@setjmp( setjmp(jb); // CHECK: call {{.*}}@sigsetjmp( @@ -28,6 +34,10 @@ void f(void) { _setjmp(jb); // CHECK: call {{.*}}@__sigsetjmp( __sigsetjmp(jb, 0); + // CHECK: call {{.*}}@_setjmpex( + _setjmpex(jb); + // CHECK: call {{.*}}@getcontext( + getcontext(ut); } // CHECK: ; Function Attrs: returns_twice @@ -42,3 +52,8 @@ void f(void) { // CHECK: ; Function Attrs: returns_twice // CHECK-NEXT: declare {{.*}} @__sigsetjmp( +// CHECK: ; Function Attrs: returns_twice +// CHECK-NEXT: declare {{.*}} @_setjmpex( + +// CHECK: ; Function Attrs: returns_twice +// CHECK-NEXT: declare {{.*}} @getcontext( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits