Only lower __builtin_setjmp / __builtin_longjmp to
authorJoerg Sonnenberger <joerg@bec.de>
Mon, 23 Feb 2015 20:23:47 +0000 (20:23 +0000)
committerJoerg Sonnenberger <joerg@bec.de>
Mon, 23 Feb 2015 20:23:47 +0000 (20:23 +0000)
llvm.eh.sjlj.setjmp / llvm.eh.sjlj.longjmp, if the backend is known to
support them outside the Exception Handling context. The default
handling in LLVM codegen doesn't work and will create incorrect code.
The ARM backend on the other hand will assert if the intrinsics are
used.

llvm-svn: 230255

clang/include/clang/Basic/Builtins.def
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/CodeGen/TargetInfo.cpp
clang/lib/CodeGen/TargetInfo.h
clang/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c [deleted file]
clang/test/CodeGen/builtin-longjmp.c [new file with mode: 0644]

index 29fd7b4..632509b 100644 (file)
@@ -448,8 +448,8 @@ BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
 BUILTIN(__builtin_frame_address, "v*IUi", "n")
 BUILTIN(__builtin___clear_cache, "vc*c*", "n")
 BUILTIN(__builtin_flt_rounds, "i", "nc")
-BUILTIN(__builtin_setjmp, "iv**", "j")
-BUILTIN(__builtin_longjmp, "vv**i", "r")
+BUILTIN(__builtin_setjmp, "iv**", "Fj")
+BUILTIN(__builtin_longjmp, "vv**i", "Fr")
 BUILTIN(__builtin_unwind_init, "v", "")
 BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc")
 BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:")
index 859ad3e..3d9a83d 100644 (file)
@@ -859,6 +859,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
       return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext"));
   }
   case Builtin::BI__builtin_setjmp: {
+    if (!getTargetHooks().hasSjLjLowering(*this))
+      break;
     // Buffer is a void**.
     Value *Buf = EmitScalarExpr(E->getArg(0));
 
@@ -881,6 +883,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
     return RValue::get(Builder.CreateCall(F, Buf));
   }
   case Builtin::BI__builtin_longjmp: {
+    if (!getTargetHooks().hasSjLjLowering(*this))
+      break;
     Value *Buf = EmitScalarExpr(E->getArg(0));
     Buf = Builder.CreateBitCast(Buf, Int8PtrTy);
 
index 8070e31..814a0b4 100644 (file)
@@ -665,6 +665,9 @@ public:
     return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
   }
 
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return true;
+  }
 };
 
 }
@@ -1599,6 +1602,10 @@ public:
   unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
     return HasAVX ? 32 : 16;
   }
+
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return true;
+  }
 };
 
 class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
@@ -3116,6 +3123,10 @@ public:
   unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
     return 16; // Natural alignment for Altivec vectors.
   }
+
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return true;
+  }
 };
 
 }
@@ -3328,6 +3339,10 @@ public:
   unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
     return 16; // Natural alignment for Altivec and VSX vectors.
   }
+
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return true;
+  }
 };
 
 class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo {
@@ -3345,6 +3360,10 @@ public:
   unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
     return 16; // Natural alignment for Altivec vectors.
   }
+
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return true;
+  }
 };
 
 }
@@ -4462,6 +4481,12 @@ public:
                                               llvm::AttributeSet::FunctionIndex,
                                               B));
   }
+
+  bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override {
+    return false;
+    // FIXME: backend implementation too restricted, even on Darwin.
+    // return CGF.getTarget().getTriple().isOSDarwin();
+  }
 };
 
 class WindowsARMTargetCodeGenInfo : public ARMTargetCodeGenInfo {
index cc469d6..87f1376 100644 (file)
@@ -225,6 +225,13 @@ public:
   virtual unsigned getOpenMPSimdDefaultAlignment(QualType Type) const {
     return 0;
   }
+
+  /// Control whether __builtin_longjmp / __builtin_setjmp are lowered to
+  /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp or the normal library
+  /// function.
+  virtual bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const {
+    return false;
+  }
 };
 }
 
diff --git a/clang/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c b/clang/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c
deleted file mode 100644 (file)
index 3aa5c00..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* RUN: %clang_cc1  %s -emit-llvm -o - | FileCheck %s
- *
- * __builtin_longjmp/setjmp should get transformed into intrinsics.
- */
-
-// CHECK-NOT: builtin_longjmp
-
-void jumpaway(int *ptr) {
-  __builtin_longjmp(ptr,1);
-}
-    
-int main(void) {
-  __builtin_setjmp(0);
-  jumpaway(0);
-}
diff --git a/clang/test/CodeGen/builtin-longjmp.c b/clang/test/CodeGen/builtin-longjmp.c
new file mode 100644 (file)
index 0000000..75c91b8
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=SUPPORTED
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=SUPPORTED
+// RUN: %clang_cc1 -triple powerpc-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=SUPPORTED
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=SUPPORTED
+// RUN: %clang_cc1 -triple arm-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=UNSUPPORTED
+// RUN: %clang_cc1 -triple aarch64-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=UNSUPPORTED
+// RUN: %clang_cc1 -triple mips-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=UNSUPPORTED
+// RUN: %clang_cc1 -triple mips64-unknown-unknown -emit-llvm < %s| FileCheck %s -check-prefix=UNSUPPORTED
+
+// Check that __builtin_longjmp and __builtin_setjmp are lowerd into
+// IR intrinsics on those architectures that can handle them.
+// Check that they are lowered to the libcalls on other architectures.
+
+typedef void *jmp_buf;
+jmp_buf buf;
+
+// SUPPORTED:   define{{.*}} void @do_jump()
+// SUPPORTED:   call{{.*}} void @llvm.eh.sjlj.longjmp
+// UNSUPPORTED: define{{.*}} void @do_jump()
+// UNSUPPORTED: call{{.*}} void @longjmp
+
+// SUPPORTED:   define{{.*}} void @do_setjmp()
+// SUPPORTED:   call{{.*}} i32 @llvm.eh.sjlj.setjmp
+// UNSUPPORTED: define{{.*}} void @do_setjmp()
+// UNSUPPORTED: call{{.*}} i32 @setjmp
+
+void do_jump(void) {
+  __builtin_longjmp(buf, 1);
+}
+
+void f(void);
+
+void do_setjmp(void) {
+  if (!__builtin_setjmp(buf))
+    f();
+}