Index: include/llvm/CodeGen/MachineFrameInfo.h =================================================================== --- include/llvm/CodeGen/MachineFrameInfo.h +++ include/llvm/CodeGen/MachineFrameInfo.h @@ -35,6 +35,11 @@ int FrameIdx; unsigned DstReg; }; + + // Windows exception handling requires callee saved registers to be saved + // for EH funclets separately from the main function. + int FuncletFrameIdx; + /// Flag indicating whether the register is actually restored in the epilog. /// In most cases, if a register is saved, it is also restored. There are /// some situations, though, when this is not the case. For example, the @@ -54,7 +59,8 @@ public: explicit CalleeSavedInfo(unsigned R, int FI = 0) - : Reg(R), FrameIdx(FI), Restored(true), SpilledToReg(false) {} + : Reg(R), FrameIdx(FI), FuncletFrameIdx(0), Restored(true), + SpilledToReg(false) {} // Accessors. unsigned getReg() const { return Reg; } @@ -68,6 +74,10 @@ DstReg = SpillReg; SpilledToReg = true; } + + int getFuncletFrameIdx() const { return FuncletFrameIdx; } + void setFuncletFrameIdx(int FI) { FuncletFrameIdx = FI; } + bool isRestored() const { return Restored; } void setRestored(bool R) { Restored = R; } bool isSpilledToReg() const { return SpilledToReg; } Index: lib/Target/X86/X86FrameLowering.cpp =================================================================== --- lib/Target/X86/X86FrameLowering.cpp +++ lib/Target/X86/X86FrameLowering.cpp @@ -2015,6 +2015,34 @@ MFI.ensureMaxAlignment(Align); } + // If this function has funclets, create extra slots for non-GPRs in the + // funclets. + if (MF.hasEHFunclets()) { + for (unsigned i = CSI.size(); i != 0; --i) { + unsigned Reg = CSI[i - 1].getReg(); + if (X86::GR64RegClass.contains(Reg) || X86::GR32RegClass.contains(Reg)) + continue; + + // FIXME: I'm not sure all of this is necessary, but it will work. + + // If this is k-register make sure we lookup via the largest legal type. + MVT VT = MVT::Other; + if (X86::VK16RegClass.contains(Reg)) + VT = STI.hasBWI() ? MVT::v64i1 : MVT::v16i1; + + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg, VT); + unsigned Size = TRI->getSpillSize(*RC); + unsigned Align = TRI->getSpillAlignment(*RC); + // ensure alignment + SpillSlotOffset -= std::abs(SpillSlotOffset) % Align; + // spill into slot + SpillSlotOffset -= Size; + int SlotIndex = MFI.CreateFixedSpillStackObject(Size, SpillSlotOffset); + CSI[i - 1].setFuncletFrameIdx(SlotIndex); + MFI.ensureMaxAlignment(Align); + } + } + return true; } @@ -2080,8 +2108,9 @@ MBB.addLiveIn(Reg); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg, VT); - TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i - 1].getFrameIdx(), RC, - TRI); + int FrameIdx = (MBB.isEHFuncletEntry() ? CSI[i - 1].getFuncletFrameIdx() + : CSI[i - 1].getFrameIdx()); + TII.storeRegToStackSlot(MBB, MI, Reg, true, FrameIdx, RC, TRI); --MI; MI->setFlag(MachineInstr::FrameSetup); ++MI; @@ -2126,8 +2155,9 @@ const TargetRegisterInfo *TRI) const { if (CSI.empty()) return false; - - if (MI != MBB.end() && isFuncletReturnInstr(*MI) && STI.isOSWindows()) { + bool IsEHFuncletReturn = + (MI != MBB.end() && isFuncletReturnInstr(*MI) && STI.isOSWindows()); + if (IsEHFuncletReturn) { // Don't restore CSRs in 32-bit EH funclets. Matches // spillCalleeSavedRegisters. if (STI.is32Bit()) @@ -2158,7 +2188,9 @@ VT = STI.hasBWI() ? MVT::v64i1 : MVT::v16i1; const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg, VT); - TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI); + int FrameIdx = (IsEHFuncletReturn ? CSI[i].getFuncletFrameIdx() + : CSI[i].getFrameIdx()); + TII.loadRegFromStackSlot(MBB, MI, Reg, FrameIdx, RC, TRI); } // POP GPRs. Index: test/CodeGen/X86/catchpad-realign-savexmm.ll =================================================================== --- test/CodeGen/X86/catchpad-realign-savexmm.ll +++ test/CodeGen/X86/catchpad-realign-savexmm.ll @@ -30,14 +30,14 @@ ; CHECK: f: # @f ; CHECK: pushq %rbp ; CHECK: .seh_pushreg 5 -; CHECK: subq $64, %rsp -; CHECK: .seh_stackalloc 64 -; CHECK: leaq 64(%rsp), %rbp -; CHECK: .seh_setframe 5, 64 +; CHECK: subq $80, %rsp +; CHECK: .seh_stackalloc 80 +; CHECK: leaq 80(%rsp), %rbp +; CHECK: .seh_setframe 5, 80 ; CHECK: movaps %xmm6, -16(%rbp) # 16-byte Spill -; CHECK: .seh_savexmm 6, 48 +; CHECK: .seh_savexmm 6, 64 ; CHECK: .seh_endprologue -; CHECK: movq $-2, -24(%rbp) +; CHECK: movq $-2, -40(%rbp) ; CHECK: movsd fp_global(%rip), %xmm6 # xmm6 = mem[0],zero ; CHECK: callq g ; CHECK: addsd __real@3ff0000000000000(%rip), %xmm6 @@ -47,7 +47,26 @@ ; CHECK: .Ltmp{{.*}} ; CHECK: .LBB{{.*}} # Block address taken ; CHECK: movaps -16(%rbp), %xmm6 -; CHECK: addq $64, %rsp +; CHECK: addq $80, %rsp ; CHECK: popq %rbp ; CHECK: retq ; CHECK: .seh_handlerdata + +; CHECK: "?catch$2@?0?f@4HA": +; CHECK: .seh_proc "?catch$2@?0?f@4HA" +; CHECK: .seh_handler __CxxFrameHandler3, @unwind, @except +; CHECK: .LBB0{{.*}} # %catch +; CHECK: movq %rdx, 16(%rsp) +; CHECK: pushq %rbp +; CHECK: .seh_pushreg 5 +; CHECK: subq $32, %rsp +; CHECK: .seh_stackalloc 32 +; CHECK: leaq 80(%rdx), %rbp +; CHECK: movapd %xmm6, -32(%rbp) # 16-byte Spill +; CHECK: .seh_savexmm 6, 48 +; CHECK: .seh_endprologue +; CHECK: movapd -32(%rbp), %xmm6 # 16-byte Reload +; CHECK: leaq .LBB{{.*}}(%rip), %rax +; CHECK: addq $32, %rsp +; CHECK: popq %rbp +; CHECK: retq # CATCHRET