forked from OSchip/llvm-project
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
This commit is contained in:
parent
b9bf14c549
commit
310e3a8f60
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]]
|
||||
}
|
Loading…
Reference in New Issue