ASTContext &Context = CGF.getContext();
CodeGenModule &CGM = CGF.CGM;
- // In 64-bit, we call the child function with arguments. In 32-bit, we store
- // zero in the parent frame and use framerecover to check the value.
- const CGFunctionInfo *FnInfo;
CallArgList Args;
- if (CGF.getTarget().getTriple().getArch() != llvm::Triple::x86) {
- // Compute the two argument values.
- QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
- llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
- llvm::Value *FP =
- CGF.Builder.CreateCall(FrameAddr, {CGF.Builder.getInt32(0)});
- llvm::Value *IsForEH =
- llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
- Args.add(RValue::get(IsForEH), ArgTys[0]);
- Args.add(RValue::get(FP), ArgTys[1]);
-
- // Arrange a two-arg function info and type.
- FunctionProtoType::ExtProtoInfo EPI;
- const auto *FPT = cast<FunctionProtoType>(
- Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
- FnInfo = &CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
- /*chainCall=*/false);
- } else {
- // Emit the zero store if this is normal control flow. There are no
- // explicit arguments.
- if (F.isForNormalCleanup() && CGF.ChildAbnormalTerminationSlot)
- CGF.Builder.CreateStore(CGF.Builder.getInt32(0),
- CGF.ChildAbnormalTerminationSlot);
- FnInfo = &CGM.getTypes().arrangeNullaryFunction();
- }
- CGF.EmitCall(*FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
+ // Compute the two argument values.
+ QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
+ llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
+ llvm::Value *FP =
+ CGF.Builder.CreateCall(FrameAddr, {CGF.Builder.getInt32(0)});
+ llvm::Value *IsForEH =
+ llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+ Args.add(RValue::get(IsForEH), ArgTys[0]);
+ Args.add(RValue::get(FP), ArgTys[1]);
+
+ // Arrange a two-arg function info and type.
+ FunctionProtoType::ExtProtoInfo EPI;
+ const auto *FPT = cast<FunctionProtoType>(
+ Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
+ /*chainCall=*/false);
+
+ CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
}
};
}
CodeGenFunction &ParentCGF;
const VarDecl *ParentThis;
SmallVector<const VarDecl *, 4> Captures;
- llvm::Value *AbnormalTermination = nullptr;
llvm::Value *SEHCodeSlot = nullptr;
CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
: ParentCGF(ParentCGF), ParentThis(ParentThis) {}
// Return true if we need to do any capturing work.
bool foundCaptures() {
- return !Captures.empty() || AbnormalTermination || SEHCodeSlot;
+ return !Captures.empty() || SEHCodeSlot;
}
void Visit(const Stmt *S) {
unsigned ID = E->getBuiltinCallee();
switch (ID) {
- case Builtin::BI__abnormal_termination:
- case Builtin::BI_abnormal_termination:
- // This is the simple case where we are the outermost finally. All we
- // have to do here is make sure we escape this and recover it in the
- // outlined handler.
- if (!AbnormalTermination)
- AbnormalTermination = ParentCGF.CreateMemTemp(
- ParentCGF.getContext().IntTy, "abnormal_termination");
- break;
case Builtin::BI__exception_code:
case Builtin::BI_exception_code:
// This is the simple case where we are the outermost finally. All we
recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
}
- // The __abnormal_termination and __exception_code values are just more
- // captures.
- if (Finder.AbnormalTermination) {
- AbnormalTerminationSlot = recoverAddrOfEscapedLocal(
- ParentCGF, Finder.AbnormalTermination, ParentFP);
- // Save the slot on the parent so it can store 1 and 0 to it.
- ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination;
- }
-
if (Finder.SEHCodeSlot) {
SEHCodeSlotStack.push_back(
recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP));
}
FunctionArgList Args;
- if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
+ if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) {
+ // All SEH finally functions take two parameters. Win64 filters take two
+ // parameters. Win32 filters take no parameters.
if (IsFilter) {
Args.push_back(ImplicitParamDecl::Create(
getContext(), nullptr, StartLoc,
}
llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
- if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
- return Builder.CreateLoad(AbnormalTerminationSlot);
// Abnormal termination is just the first parameter to the outlined finally
// helper.
auto AI = CurFn->arg_begin();
llvm::Function *FinallyFunc =
HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
- // Store 1 to indicate abnormal termination if an exception is thrown.
- if (ChildAbnormalTerminationSlot)
- Builder.CreateStore(Builder.getInt32(1), ChildAbnormalTerminationSlot);
-
// Push a cleanup for __finally blocks.
EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
return;
// Just pop the cleanup if it's a __finally block.
if (S.getFinallyHandler()) {
PopCleanupBlock();
- ChildAbnormalTerminationSlot = nullptr;
return;
}
-// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \
-// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \
-// RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
void abort(void) __attribute__((noreturn));
void might_crash(void);
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
// CHECK-NEXT: ret void
//
// CHECK: [[lpad]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
// CHECK: resume { i8*, i32 }
// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}})
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@label_in_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@label_in_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
// CHECK: ret void
// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"({{.*}})
}
// CHECK-LABEL: define void @use_abnormal_termination()
-// X86: call void (...) @llvm.frameescape(i32* %[[abnormal_termination:[^ ),]*]])
-// X86: store i32 1, i32* %[[abnormal_termination]]
// CHECK: invoke void @might_crash()
// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
//
// CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]])
-// X86: store i32 0, i32* %[[abnormal_termination]]
-// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
// CHECK: ret void
//
// CHECK: [[lpad]]
// CHECK-NEXT: landingpad
// CHECK-NEXT: cleanup
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
// CHECK: resume { i8*, i32 }
-// X64: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %[[abnormal:abnormal_termination]], i8* %frame_pointer)
-// X64: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
-// X86: define internal void @"\01?fin$0@0@use_abnormal_termination@@"()
-// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
-// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @use_abnormal_termination to i8*), i8* %[[ebp]])
-// X86: %[[abnormal_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @use_abnormal_termination to i8*), i8* %[[fp]], i32 0)
-// X86: %[[abnormal:[^ ]*]] = bitcast i8* %[[abnormal_i8]] to i32*
-// X86: %[[abnormal_zext:[^ ]*]] = load i32, i32* %[[abnormal]]
+// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
// CHECK: store i32 %[[abnormal_zext]], i32* @crashed
// CHECK-NEXT: ret void