Skip to content

Commit

Permalink
[X86] Only force FP usage in the presence of pushf/popf on Win64
Browse files Browse the repository at this point in the history
This ensures that the Windows unwinder will work at every instruction
boundary, and allows other targets to read and write flags without
setting up a frame pointer.

Fixes llvmGH-46875

Differential Revision: https://reviews.llvm.org/D119391
  • Loading branch information
rnk committed Feb 10, 2022
1 parent 0148b58 commit f3481f4
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 31 deletions.
5 changes: 4 additions & 1 deletion llvm/lib/Target/X86/X86FrameLowering.cpp
Expand Up @@ -100,7 +100,7 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF) const {
MF.getInfo<X86MachineFunctionInfo>()->hasPreallocatedCall() ||
MF.callsUnwindInit() || MF.hasEHFunclets() || MF.callsEHReturn() ||
MFI.hasStackMap() || MFI.hasPatchPoint() ||
MFI.hasCopyImplyingStackAdjustment());
(isWin64Prologue(MF) && MFI.hasCopyImplyingStackAdjustment()));
}

static unsigned getSUBriOpcode(bool IsLP64, int64_t Imm) {
Expand Down Expand Up @@ -1385,6 +1385,9 @@ bool X86FrameLowering::has128ByteRedZone(const MachineFunction& MF) const {
return Is64Bit && !IsWin64CC && !Fn.hasFnAttribute(Attribute::NoRedZone);
}

/// Return true if we need to use the restricted Windows x64 prologue and
/// epilogue code patterns that can be described with WinCFI (.seh_*
/// directives).
bool X86FrameLowering::isWin64Prologue(const MachineFunction &MF) const {
return MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
}
Expand Down
61 changes: 39 additions & 22 deletions llvm/test/CodeGen/X86/x86-64-flags-intrinsics.ll
@@ -1,37 +1,54 @@
; RUN: llc -verify-machineinstrs < %s | FileCheck %s
target triple = "x86_64-pc-win32"
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -verify-machineinstrs -mtriple x86_64-linux < %s | FileCheck %s
; RUN: llc -verify-machineinstrs -mtriple x86_64-windows < %s | FileCheck %s --check-prefix=WIN64

declare i64 @llvm.x86.flags.read.u64()
declare void @llvm.x86.flags.write.u64(i64)

define i64 @read_flags() {
; CHECK-LABEL: read_flags:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushfq
; CHECK-NEXT: popq %rax
; CHECK-NEXT: retq
;
; WIN64-LABEL: read_flags:
; WIN64: # %bb.0: # %entry
; WIN64-NEXT: pushq %rbp
; WIN64-NEXT: .seh_pushreg %rbp
; WIN64-NEXT: movq %rsp, %rbp
; WIN64-NEXT: .seh_setframe %rbp, 0
; WIN64-NEXT: .seh_endprologue
; WIN64-NEXT: pushfq
; WIN64-NEXT: popq %rax
; WIN64-NEXT: popq %rbp
; WIN64-NEXT: retq
; WIN64-NEXT: .seh_endproc
entry:
%flags = call i64 @llvm.x86.flags.read.u64()
ret i64 %flags
}

; CHECK-LABEL: read_flags:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg %rbp
; CHECK: movq %rsp, %rbp
; CHECK: .seh_setframe %rbp, 0
; CHECK: .seh_endprologue
; CHECK-NEXT: pushfq
; CHECK-NEXT: popq %rax
; CHECK-NEXT: popq %rbp

define void @write_flags(i64 %arg) {
; CHECK-LABEL: write_flags:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: pushq %rdi
; CHECK-NEXT: popfq
; CHECK-NEXT: retq
;
; WIN64-LABEL: write_flags:
; WIN64: # %bb.0: # %entry
; WIN64-NEXT: pushq %rbp
; WIN64-NEXT: .seh_pushreg %rbp
; WIN64-NEXT: movq %rsp, %rbp
; WIN64-NEXT: .seh_setframe %rbp, 0
; WIN64-NEXT: .seh_endprologue
; WIN64-NEXT: pushq %rcx
; WIN64-NEXT: popfq
; WIN64-NEXT: popq %rbp
; WIN64-NEXT: retq
; WIN64-NEXT: .seh_endproc
entry:
call void @llvm.x86.flags.write.u64(i64 %arg)
ret void
}

; CHECK-LABEL: write_flags:
; CHECK: pushq %rbp
; CHECK: .seh_pushreg %rbp
; CHECK: movq %rsp, %rbp
; CHECK: .seh_setframe %rbp, 0
; CHECK: .seh_endprologue
; CHECK-NEXT: pushq %rcx
; CHECK-NEXT: popfq
; CHECK-NEXT: popq %rbp
16 changes: 8 additions & 8 deletions llvm/test/CodeGen/X86/x86-flags-intrinsics.ll
@@ -1,6 +1,10 @@
; RUN: llc -verify-machineinstrs < %s | FileCheck %s
target triple = "i686-pc-win32"

; Check that pushf/popf intrinsics on win32 don't need a frame pointer.
; FIXME: These can't be autogenerated due to the fastcall function name label,
; it seems.

declare i32 @llvm.x86.flags.read.u32()
declare void @llvm.x86.flags.write.u32(i32)

Expand All @@ -11,11 +15,9 @@ entry:
}

; CHECK-LABEL: _read_flags:
; CHECK: pushl %ebp
; CHECK-NEXT: movl %esp, %ebp
; CHECK-NEXT: pushfl
; CHECK: pushfl
; CHECK-NEXT: popl %eax
; CHECK-NEXT: popl %ebp
; CHECK-NEXT: retl

define x86_fastcallcc void @write_flags(i32 inreg %arg) {
entry:
Expand All @@ -24,8 +26,6 @@ entry:
}

; CHECK-LABEL: @write_flags@4:
; CHECK: pushl %ebp
; CHECK-NEXT: movl %esp, %ebp
; CHECK-NEXT: pushl %ecx
; CHECK: pushl %ecx
; CHECK-NEXT: popfl
; CHECK-NEXT: popl %ebp
; CHECK-NEXT: retl

0 comments on commit f3481f4

Please sign in to comment.