Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -448,8 +448,8 @@ 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: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -859,6 +859,8 @@ 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 @@ 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: lib/CodeGen/TargetInfo.h =================================================================== --- lib/CodeGen/TargetInfo.h +++ lib/CodeGen/TargetInfo.h @@ -225,6 +225,13 @@ 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; + } }; } Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -665,6 +665,9 @@ return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } + bool hasSjLjLowering(CodeGen::CodeGenFunction &CGF) const override { + return true; + } }; } @@ -1599,6 +1602,10 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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: test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c =================================================================== --- test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c +++ test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c @@ -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); -} Index: test/CodeGen/builtin-longjmp.c =================================================================== --- test/CodeGen/builtin-longjmp.c +++ 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(); +}