summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Basic/TargetInfo.h6
-rw-r--r--include/clang/Sema/Sema.h1
-rw-r--r--lib/Basic/Targets.cpp8
-rw-r--r--lib/CodeGen/TargetInfo.cpp2
-rw-r--r--lib/Sema/SemaChecking.cpp21
-rw-r--r--test/CodeGen/2003-08-06-BuiltinSetjmpLongjmp.c15
-rw-r--r--test/CodeGen/builtins.c3
-rw-r--r--test/Sema/builtin-longjmp.c34
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();
+}