diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | include/clang/Basic/TargetInfo.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Basic/Targets.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 21 | ||||
-rw-r--r-- | test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c | 15 | ||||
-rw-r--r-- | test/CodeGen/builtins.c | 3 | ||||
-rw-r--r-- | test/Sema/builtin-longjmp.c | 34 |
9 files changed, 77 insertions, 18 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b173d82a31..1a27e7cd3d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6972,6 +6972,11 @@ def note_neon_vector_initializer_non_portable_q : Note< "vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer " "constants">; +def err_builtin_longjmp_unsupported : Error< + "__builtin_longjmp is not supported for the current target">; +def err_builtin_setjmp_unsupported : Error< + "__builtin_setjmp is not supported for the current target">; + def err_builtin_longjmp_invalid_val : Error< "argument to __builtin_longjmp must be a constant 1">; def err_builtin_requires_language : Error<"'%0' is only available in %1">; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 69a5404468..7a6462c482 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -852,6 +852,12 @@ public: } } + /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to + /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp. + virtual bool hasSjLjLowering() const { + return false; + } + protected: virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return PointerWidth; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index bba7c36834..a364214c11 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8550,6 +8550,7 @@ private: bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); + bool SemaBuiltinSetjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index bf60bbf3fd..dc844bf221 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -919,6 +919,10 @@ public: if (RegNo == 1) return 4; return -1; } + + bool hasSjLjLowering() const override { + return true; + } }; const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { @@ -2181,6 +2185,10 @@ public: CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return MT == CCMT_Member ? CC_X86ThisCall : CC_C; } + + bool hasSjLjLowering() const override { + return true; + } }; bool X86TargetInfo::setFPMath(StringRef Name) { diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 39cc7e5d99..c05b23a32e 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -664,7 +664,6 @@ public: ('T' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } - }; } @@ -4455,7 +4454,6 @@ public: llvm::AttributeSet::FunctionIndex, B)); } - }; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index fdc136ccbd..8c3efdee90 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -297,6 +297,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinLongjmp(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_setjmp: + if (SemaBuiltinSetjmp(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_classify_type: if (checkArgCount(*this, TheCall, 1)) return true; @@ -2367,8 +2371,13 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, } /// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). -/// This checks that val is a constant 1. +/// This checks that the target supports __builtin_longjmp and +/// that val is a constant 1. bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { + if (!Context.getTargetInfo().hasSjLjLowering()) + return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_unsupported) + << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd()); + Expr *Arg = TheCall->getArg(1); llvm::APSInt Result; @@ -2383,6 +2392,16 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } + +/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). +/// This checks that the target supports __builtin_setjmp. +bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { + if (!Context.getTargetInfo().hasSjLjLowering()) + return Diag(TheCall->getLocStart(), diag::err_builtin_setjmp_unsupported) + << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd()); + return false; +} + namespace { enum StringLiteralCheckType { SLCT_NotALiteral, diff --git a/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c b/test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c deleted file mode 100644 index 3aa5c00397..0000000000 --- a/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/test/CodeGen/builtins.c b/test/CodeGen/builtins.c index 1ab29a659b..bf7874b088 100644 --- a/test/CodeGen/builtins.c +++ b/test/CodeGen/builtins.c @@ -220,6 +220,8 @@ void test_float_builtin_ops(float F, double D, long double LD) { // CHECK: call x86_fp80 @llvm.fabs.f80(x86_fp80 } +// __builtin_longjmp isn't supported on all platforms, so only test it on X86. +#ifdef __x86_64__ // CHECK-LABEL: define void @test_builtin_longjmp void test_builtin_longjmp(void **buffer) { // CHECK: [[BITCAST:%.*]] = bitcast @@ -227,6 +229,7 @@ void test_builtin_longjmp(void **buffer) { __builtin_longjmp(buffer, 1); // CHECK-NEXT: unreachable } +#endif // CHECK-LABEL: define i64 @test_builtin_readcyclecounter long long test_builtin_readcyclecounter() { diff --git a/test/Sema/builtin-longjmp.c b/test/Sema/builtin-longjmp.c new file mode 100644 index 0000000000..5ed393e591 --- /dev/null +++ b/test/Sema/builtin-longjmp.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm < %s| FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm < %s| FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows -emit-llvm < %s| FileCheck %s +// RUN: %clang_cc1 -triple powerpc-unknown-unknown -emit-llvm < %s| FileCheck %s +// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -emit-llvm < %s| FileCheck %s + +// RUN: %clang_cc1 -triple arm-unknown-unknown -emit-llvm-only -verify %s +// RUN: %clang_cc1 -triple aarch64-unknown-unknown -emit-llvm-only -verify %s +// RUN: %clang_cc1 -triple mips-unknown-unknown -emit-llvm-only -verify %s +// RUN: %clang_cc1 -triple mips64-unknown-unknown -emit-llvm-only -verify %s + +// Check that __builtin_longjmp and __builtin_setjmp are lowered into +// IR intrinsics on those architectures that can handle them. +// Check that an error is created otherwise. + +typedef void *jmp_buf; +jmp_buf buf; + +// CHECK: define{{.*}} void @do_jump() +// CHECK: call{{.*}} void @llvm.eh.sjlj.longjmp + +// CHECK: define{{.*}} void @do_setjmp() +// CHECK: call{{.*}} i32 @llvm.eh.sjlj.setjmp + +void do_jump(void) { + __builtin_longjmp(buf, 1); // expected-error {{__builtin_longjmp is not supported for the current target}} +} + +void f(void); + +void do_setjmp(void) { + if (!__builtin_setjmp(buf)) // expected-error {{__builtin_setjmp is not supported for the current target}} + f(); +} |