Author: Alan Zhao
Date: 2025-03-31T09:42:34-07:00
New Revision: c5b3fe209408c89c1ca21f103a8fd45fb48c3138

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

LOG: [clang] Automatically add the `returns_twice` attribute to certain 
functions even if `-fno-builtin` is set (#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

Added: 
    

Modified: 
    clang/lib/CodeGen/CGCall.cpp
    clang/test/CodeGen/2003-08-20-vfork-bug.c
    clang/test/CodeGen/setjmp.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 3a1db4f1a7a90..3cefa3b0c585c 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

Reply via email to