diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 29fd7b49cb27..632509bf896c 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -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:") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 859ad3ecd9bb..3d9a83d91c96 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -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); diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 8070e311746d..814a0b4eb092 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -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 { diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index cc469d69e390..87f13760e8e1 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -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 index 3aa5c003973f..000000000000 --- a/clang/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c +++ /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 index 000000000000..75c91b8374ff --- /dev/null +++ b/clang/test/CodeGen/builtin-longjmp.c @@ -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(); +}