Index: lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64FrameLowering.cpp +++ lib/Target/AArch64/AArch64FrameLowering.cpp @@ -919,6 +919,17 @@ if (NeedsWinCFI) BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd)) .setMIFlag(MachineInstr::FrameSetup); + + // SEH funclets are passed the frame pointer in X1. If the parent + // function uses the base register, then the base register is used + // directly, and is not retrieved from X1. + if (F.hasPersonalityFn()) { + EHPersonality Per = classifyEHPersonality(F.getPersonalityFn()); + if (isAsynchronousEHPersonality(Per)) + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP) + .addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup); + } + return; } Index: test/CodeGen/AArch64/seh_funclet_x1.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/seh_funclet_x1.ll @@ -0,0 +1,123 @@ +; RUN: llc -o - %s -mtriple=aarch64-windows | FileCheck %s + +; Windows runtime passes the establisher frame as the second argument to the +; termination handler. Check that we copy it into fp. + +; CHECK: ?dtor$3@?0?main@4HA": +; CHECK: .seh_proc "?dtor$3@?0?main@4HA" +; CHECK: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill +; CHECK-NEXT: mov x29, x1 + +target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-windows-msvc19.15.26732" + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) { +entry: + %retval = alloca i32, align 4 + %Counter = alloca i32, align 4 + %__exception_code = alloca i32, align 4 + call void (...) @llvm.localescape(i32* %Counter) + store i32 0, i32* %retval, align 4 + store i32 0, i32* %Counter, align 4 + %call = invoke i32 bitcast (i32 (...)* @RaiseStatus to i32 (i32)*)(i32 -1073741675) #5 + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + %0 = call i8* @llvm.localaddress() + invoke void @"?fin$0@0@main@@"(i8 0, i8* %0) #5 + to label %invoke.cont1 unwind label %catch.dispatch + +invoke.cont1: ; preds = %invoke.cont + br label %__try.cont + +ehcleanup: ; preds = %entry + %1 = cleanuppad within none [] + %2 = call i8* @llvm.localaddress() + invoke void @"?fin$0@0@main@@"(i8 1, i8* %2) #5 [ "funclet"(token %1) ] + to label %invoke.cont2 unwind label %catch.dispatch + +invoke.cont2: ; preds = %ehcleanup + cleanupret from %1 unwind label %catch.dispatch + +catch.dispatch: ; preds = %invoke.cont2, %ehcleanup, %invoke.cont + %3 = catchswitch within none [label %__except] unwind to caller + +__except: ; preds = %catch.dispatch + %4 = catchpad within %3 [i8* null] + catchret from %4 to label %__except3 + +__except3: ; preds = %__except + %5 = call i32 @llvm.eh.exceptioncode(token %4) + store i32 %5, i32* %__exception_code, align 4 + %6 = load i32, i32* %Counter, align 4 + %add = add nsw i32 %6, 5 + store i32 %add, i32* %Counter, align 4 + br label %__try.cont + +__try.cont: ; preds = %__except3, %invoke.cont1 + %7 = load i32, i32* %retval, align 4 + ret i32 %7 +} + +define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #1 { +entry: + %frame_pointer.addr = alloca i8*, align 8 + %abnormal_termination.addr = alloca i8, align 1 + %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0) + %Counter = bitcast i8* %0 to i32* + store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 + store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 + store i32 3, i32* %Counter, align 4 + call void @"?fin$1@0@main@@"(i8 0, i8* %frame_pointer) + %1 = load i32, i32* %Counter, align 4 + %add = add nsw i32 %1, 2 + store i32 %add, i32* %Counter, align 4 + %call = call i32 bitcast (i32 (...)* @RaiseStatus to i32 (i32)*)(i32 -1073741675) + ret void +} + +; Function Attrs: nounwind readnone +declare i8* @llvm.localrecover(i8*, i8*, i32) #2 + +define internal void @"?fin$1@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #1 { +entry: + %frame_pointer.addr = alloca i8*, align 8 + %abnormal_termination.addr = alloca i8, align 1 + %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0) + %Counter = bitcast i8* %0 to i32* + store i8* %frame_pointer, i8** %frame_pointer.addr, align 8 + store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1 + %1 = load i32, i32* %Counter, align 4 + %cmp = icmp eq i32 %1, 3 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %2 = load i32, i32* %Counter, align 4 + %add = add nsw i32 %2, 1 + store i32 %add, i32* %Counter, align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +declare dso_local i32 @RaiseStatus(...) #3 + +declare dso_local i32 @__C_specific_handler(...) + +; Function Attrs: nounwind readnone +declare i8* @llvm.localaddress() #2 + +; Function Attrs: nounwind readnone +declare i32 @llvm.eh.exceptioncode(token) #2 + +; Function Attrs: nounwind +declare void @llvm.localescape(...) #4 + +attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } +attributes #5 = { noinline }