summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2015-01-29 09:29:21 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2015-01-29 09:29:21 +0000
commit310e3a8f608fbd9162e42cc50fe316af6713113c (patch)
tree11a6d6d6ca52430343231bb24a45865311266da1
parentb9bf14c549db72ca404d83ec8a70086641303211 (diff)
downloadbcm5719-llvm-310e3a8f608fbd9162e42cc50fe316af6713113c.tar.gz
bcm5719-llvm-310e3a8f608fbd9162e42cc50fe316af6713113c.zip
MS ABI: Implement proper support for setjmp
On targets which use the MSVCRT, setjmp is a macro which expands to _setjmp or _setjmpex. _setjmp and _setjmpex have a secret, hidden argument which is not listed in the function prototype on X64 and WoA. This hidden argument always seems to be the frame pointer. _setjmpex isn't used on X86, _setjmp is magically replaced with a call to _setjmp3. The second argument is zero for 'normal' setjmp/longjmp pairs, otherwise it is a count of additional variadic arguments. This is used when setjmp appears inside of a try or __try. It is not safe to use a pointer to setjmp because _setjmp, _setjmpex and _setmp3 are not compatible with setjmp. llvm-svn: 227426
-rw-r--r--clang/include/clang/Basic/Builtins.def3
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp52
-rw-r--r--clang/test/CodeGen/ms-setjmp.c29
3 files changed, 84 insertions, 0 deletions
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index 0526cb4481a..acfef18d75e 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -710,6 +710,9 @@ LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__readfsdword, "ULiULi", "n", ALL_MS_LANGUAGES)
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
+// Microsoft library builtins.
+LIBBUILTIN(_setjmpex, "iJ", "fj", "setjmpex.h", ALL_MS_LANGUAGES)
+
// C99 library functions
// C99 stdlib.h
LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES)
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ee8aa12b680..f192788c787 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Intrinsics.h"
@@ -1662,6 +1663,57 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
case Builtin::BI__exception_info:
case Builtin::BI_exception_info:
return RValue::get(EmitSEHExceptionInfo());
+ case Builtin::BI_setjmpex: {
+ if (getTarget().getTriple().isOSMSVCRT()) {
+ llvm::Type *ArgTypes[] = {Int8PtrTy, Int8PtrTy};
+ llvm::AttributeSet ReturnsTwiceAttr =
+ AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::ReturnsTwice);
+ llvm::Constant *SetJmpEx = CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(IntTy, ArgTypes, /*isVarArg=*/false),
+ "_setjmpex", ReturnsTwiceAttr);
+ llvm::Value *Buf =
+ Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int8PtrTy);
+ llvm::Value *FrameAddr =
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
+ ConstantInt::get(Int32Ty, 0));
+ llvm::Value *Args[] = {Buf, FrameAddr};
+ llvm::CallSite CS = EmitRuntimeCallOrInvoke(SetJmpEx, Args);
+ CS.setAttributes(ReturnsTwiceAttr);
+ return RValue::get(CS.getInstruction());
+ }
+ }
+ case Builtin::BI_setjmp: {
+ if (getTarget().getTriple().isOSMSVCRT()) {
+ llvm::AttributeSet ReturnsTwiceAttr =
+ AttributeSet::get(getLLVMContext(), llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::ReturnsTwice);
+ llvm::Value *Buf =
+ Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)), Int8PtrTy);
+ llvm::CallSite CS;
+ if (getTarget().getTriple().getArch() == llvm::Triple::x86) {
+ llvm::Type *ArgTypes[] = {Int8PtrTy, IntTy};
+ llvm::Constant *SetJmp3 = CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(IntTy, ArgTypes, /*isVarArg=*/true),
+ "_setjmp3", ReturnsTwiceAttr);
+ llvm::Value *Count = ConstantInt::get(IntTy, 0);
+ llvm::Value *Args[] = {Buf, Count};
+ CS = EmitRuntimeCallOrInvoke(SetJmp3, Args);
+ } else {
+ llvm::Type *ArgTypes[] = {Int8PtrTy, Int8PtrTy};
+ llvm::Constant *SetJmp = CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(IntTy, ArgTypes, /*isVarArg=*/false),
+ "_setjmp", ReturnsTwiceAttr);
+ llvm::Value *FrameAddr =
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
+ ConstantInt::get(Int32Ty, 0));
+ llvm::Value *Args[] = {Buf, FrameAddr};
+ CS = EmitRuntimeCallOrInvoke(SetJmp, Args);
+ }
+ CS.setAttributes(ReturnsTwiceAttr);
+ return RValue::get(CS.getInstruction());
+ }
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/test/CodeGen/ms-setjmp.c b/clang/test/CodeGen/ms-setjmp.c
new file mode 100644
index 00000000000..5073e08773b
--- /dev/null
+++ b/clang/test/CodeGen/ms-setjmp.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fms-extensions -triple i686-windows-msvc -emit-llvm %s -o - | FileCheck --check-prefix=I386 %s
+// RUN: %clang_cc1 -fms-extensions -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck --check-prefix=X64 %s
+
+typedef char jmp_buf[1];
+
+int _setjmp(jmp_buf env);
+int _setjmpex(jmp_buf env);
+
+jmp_buf jb;
+
+int test_setjmp() {
+ return _setjmp(jb);
+ // I386-LABEL: define i32 @test_setjmp
+ // I386: %[[call:.*]] = call i32 (i8*, i32, ...)* @_setjmp3(i8* getelementptr inbounds ([1 x i8]* @jb, i32 0, i32 0), i32 0)
+ // I386-NEXT: ret i32 %[[call]]
+
+ // X64-LABEL: define i32 @test_setjmp
+ // X64: %[[addr:.*]] = call i8* @llvm.frameaddress(i32 0)
+ // X64: %[[call:.*]] = call i32 @_setjmp(i8* getelementptr inbounds ([1 x i8]* @jb, i32 0, i32 0), i8* %[[addr]])
+ // X64-NEXT: ret i32 %[[call]]
+}
+
+int test_setjmpex() {
+ return _setjmpex(jb);
+ // X64-LABEL: define i32 @test_setjmpex
+ // X64: %[[addr:.*]] = call i8* @llvm.frameaddress(i32 0)
+ // X64: %[[call:.*]] = call i32 @_setjmpex(i8* getelementptr inbounds ([1 x i8]* @jb, i32 0, i32 0), i8* %[[addr]])
+ // X64-NEXT: ret i32 %[[call]]
+}
OpenPOWER on IntegriCloud