trans: Reimplement unwinding on MSVC

This commit transitions the compiler to using the new exception handling
instructions in LLVM for implementing unwinding for MSVC. This affects both 32
and 64-bit MSVC as they're both now using SEH-based strategies. In terms of
standard library support, lots more details about how SEH unwinding is
implemented can be found in the commits.

In terms of trans, this change necessitated a few modifications:

* Branches were added to detect when the old landingpad instruction is used or
  the new cleanuppad instruction is used to `trans::cleanup`.
* The return value from `cleanuppad` is not stored in an `alloca` (because it
  cannot be).
* Each block in trans now has an `Option<LandingPad>` instead of `is_lpad: bool`
  for indicating whether it's in a landing pad or not. The new exception
  handling intrinsics require that on MSVC each `call` inside of a landing pad
  is annotated with which landing pad that it's in. This change to the basic
  block means that whenever a `call` or `invoke` instruction is generated we
  know whether to annotate it as part of a cleanuppad or not.
* Lots of modifications were made to the instruction builders to construct the
  new instructions as well as pass the tagging information for the call/invoke
  instructions.
* The translation of the `try` intrinsics for MSVC has been overhauled to use
  the new `catchpad` instruction. The filter function is now also a
  rustc-generated function instead of a purely libstd-defined function. The
  libstd definition still exists, it just has a stable ABI across architectures
  and leaves some of the really weird implementation details to the compiler
  (e.g. the `localescape` and `localrecover` intrinsics).
This commit is contained in:
Alex Crichton 2015-10-23 18:18:44 -07:00
parent d1cace17af
commit 3e9589c0f4
21 changed files with 1126 additions and 420 deletions

View file

@ -987,3 +987,181 @@ LLVMRustBuildLandingPad(LLVMBuilderRef Builder,
LLVMValueRef F) {
return LLVMBuildLandingPad(Builder, Ty, PersFn, NumClauses, Name);
}
extern "C" LLVMValueRef
LLVMRustBuildCleanupPad(LLVMBuilderRef Builder,
LLVMValueRef ParentPad,
unsigned ArgCnt,
LLVMValueRef *LLArgs,
const char *Name) {
#if LLVM_VERSION_MINOR >= 8
Value **Args = unwrap(LLArgs);
if (ParentPad == NULL) {
Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
ParentPad = wrap(Constant::getNullValue(Ty));
}
return wrap(unwrap(Builder)->CreateCleanupPad(unwrap(ParentPad),
ArrayRef<Value*>(Args, ArgCnt),
Name));
#else
return NULL;
#endif
}
extern "C" LLVMValueRef
LLVMRustBuildCleanupRet(LLVMBuilderRef Builder,
LLVMValueRef CleanupPad,
LLVMBasicBlockRef UnwindBB) {
#if LLVM_VERSION_MINOR >= 8
CleanupPadInst *Inst = cast<CleanupPadInst>(unwrap(CleanupPad));
return wrap(unwrap(Builder)->CreateCleanupRet(Inst, unwrap(UnwindBB)));
#else
return NULL;
#endif
}
extern "C" LLVMValueRef
LLVMRustBuildCatchPad(LLVMBuilderRef Builder,
LLVMValueRef ParentPad,
unsigned ArgCnt,
LLVMValueRef *LLArgs,
const char *Name) {
#if LLVM_VERSION_MINOR >= 8
Value **Args = unwrap(LLArgs);
return wrap(unwrap(Builder)->CreateCatchPad(unwrap(ParentPad),
ArrayRef<Value*>(Args, ArgCnt),
Name));
#else
return NULL;
#endif
}
extern "C" LLVMValueRef
LLVMRustBuildCatchRet(LLVMBuilderRef Builder,
LLVMValueRef Pad,
LLVMBasicBlockRef BB) {
#if LLVM_VERSION_MINOR >= 8
return wrap(unwrap(Builder)->CreateCatchRet(cast<CatchPadInst>(unwrap(Pad)),
unwrap(BB)));
#else
return NULL;
#endif
}
extern "C" LLVMValueRef
LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder,
LLVMValueRef ParentPad,
LLVMBasicBlockRef BB,
unsigned NumHandlers,
const char *Name) {
#if LLVM_VERSION_MINOR >= 8
if (ParentPad == NULL) {
Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
ParentPad = wrap(Constant::getNullValue(Ty));
}
return wrap(unwrap(Builder)->CreateCatchSwitch(unwrap(ParentPad),
unwrap(BB),
NumHandlers,
Name));
#else
return NULL;
#endif
}
extern "C" void
LLVMRustAddHandler(LLVMValueRef CatchSwitchRef,
LLVMBasicBlockRef Handler) {
#if LLVM_VERSION_MINOR >= 8
Value *CatchSwitch = unwrap(CatchSwitchRef);
cast<CatchSwitchInst>(CatchSwitch)->addHandler(unwrap(Handler));
#endif
}
extern "C" void
LLVMRustSetPersonalityFn(LLVMBuilderRef B,
LLVMValueRef Personality) {
#if LLVM_VERSION_MINOR >= 8
unwrap(B)->GetInsertBlock()
->getParent()
->setPersonalityFn(cast<Function>(unwrap(Personality)));
#endif
}
#if LLVM_VERSION_MINOR >= 8
extern "C" OperandBundleDef*
LLVMRustBuildOperandBundleDef(const char *Name,
LLVMValueRef *Inputs,
unsigned NumInputs) {
return new OperandBundleDef(Name, makeArrayRef(unwrap(Inputs), NumInputs));
}
extern "C" void
LLVMRustFreeOperandBundleDef(OperandBundleDef* Bundle) {
delete Bundle;
}
extern "C" LLVMValueRef
LLVMRustBuildCall(LLVMBuilderRef B,
LLVMValueRef Fn,
LLVMValueRef *Args,
unsigned NumArgs,
OperandBundleDef *Bundle,
const char *Name) {
unsigned len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, len);
return wrap(unwrap(B)->CreateCall(unwrap(Fn),
makeArrayRef(unwrap(Args), NumArgs),
Bundles,
Name));
}
extern "C" LLVMValueRef
LLVMRustBuildInvoke(LLVMBuilderRef B,
LLVMValueRef Fn,
LLVMValueRef *Args,
unsigned NumArgs,
LLVMBasicBlockRef Then,
LLVMBasicBlockRef Catch,
OperandBundleDef *Bundle,
const char *Name) {
unsigned len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, len);
return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch),
makeArrayRef(unwrap(Args), NumArgs),
Bundles,
Name));
}
#else
extern "C" void*
LLVMRustBuildOperandBundleDef(const char *Name,
LLVMValueRef *Inputs,
unsigned NumInputs) {
return NULL;
}
extern "C" void
LLVMRustFreeOperandBundleDef(void* Bundle) {
}
extern "C" LLVMValueRef
LLVMRustBuildCall(LLVMBuilderRef B,
LLVMValueRef Fn,
LLVMValueRef *Args,
unsigned NumArgs,
void *Bundle,
const char *Name) {
return LLVMBuildCall(B, Fn, Args, NumArgs, Name);
}
extern "C" LLVMValueRef
LLVMRustBuildInvoke(LLVMBuilderRef B,
LLVMValueRef Fn,
LLVMValueRef *Args,
unsigned NumArgs,
LLVMBasicBlockRef Then,
LLVMBasicBlockRef Catch,
void *Bundle,
const char *Name) {
return LLVMBuildInvoke(B, Fn, Args, NumArgs, Then, Catch, Name);
}
#endif