Index: lib/Target/X86/X86VZeroUpper.cpp =================================================================== --- lib/Target/X86/X86VZeroUpper.cpp +++ lib/Target/X86/X86VZeroUpper.cpp @@ -80,6 +80,7 @@ BlockStateMap BlockStates; DirtySuccessorsWorkList DirtySuccessors; bool EverMadeChange; + bool IsX86INTR; const TargetInstrInfo *TII; static char ID; @@ -181,10 +182,13 @@ for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) { MachineInstr *MI = I; + // No need for vzeroupper before iret in interrupt handler function, + // epilogue will restore YMM registers if needed. + bool isReturnFromX86INTR = IsX86INTR && MI->isReturn(); bool isControlFlow = MI->isCall() || MI->isReturn(); // Shortcut: don't need to check regular instructions in dirty state. - if (!isControlFlow && CurState == EXITS_DIRTY) + if ((!isControlFlow || isReturnFromX86INTR) && CurState == EXITS_DIRTY) continue; if (hasYmmReg(MI)) { @@ -196,7 +200,7 @@ // Check for control-flow out of the current function (which might // indirectly execute SSE instructions). - if (!isControlFlow) + if (!isControlFlow || isReturnFromX86INTR) continue; // If the call won't clobber any YMM register, skip it as well. It usually @@ -253,6 +257,7 @@ TII = ST.getInstrInfo(); MachineRegisterInfo &MRI = MF.getRegInfo(); EverMadeChange = false; + IsX86INTR = MF.getFunction()->getCallingConv() == CallingConv::X86_INTR; bool FnHasLiveInYmm = checkFnHasLiveInYmm(MRI); Index: test/CodeGen/X86/x86-interrupt_vzeroupper.ll =================================================================== --- test/CodeGen/X86/x86-interrupt_vzeroupper.ll +++ test/CodeGen/X86/x86-interrupt_vzeroupper.ll @@ -0,0 +1,41 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Checks that interrupt handler code does not call "vzeroupper" instruction +;; before iret. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Command line: -mavx -S -o - -emit-llvm -O2 +;; Source: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;extern void foo (void *) __attribute__ ((interrupt)); +;;extern void bar (void); +;; +;;void foo (void *frame) +;;{ +;; bar (); +;;} +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; CHECK: vzeroupper +; CHECK-NEXT: call +; CHECK-NOT: vzeroupper +; CHECK: iret + +@llvm.used = appending global [1 x i8*] [i8* bitcast (void (i8*)* @foo to i8*)], section "llvm.metadata" + +; Function Attrs: nounwind +define x86_intrcc void @foo(i8* nocapture readnone %frame) #0 { +entry: + tail call void @bar() #2 + ret void +} + +declare void @bar() #1 + +attributes #0 = { nounwind "disable-tail-calls"="true" "stackrealign" "target-features"="+avx" } +attributes #1 = { "target-features"="+avx" } +attributes #2 = { nounwind } + +!llvm.ident = !{!0} + +!0 = !{!"clang version 3.9.0 (trunk 259349) (llvm/trunk 259357)"}