Use a tri-state enum to represent shouldUseFramePointer() and
shouldUseLeafFramePointer().
This simplifies the logic and fixes PR9825:
-fno-omit-frame-pointer doesn't imply -mno-omit-leaf-frame-pointer.
and PR24003:
/Oy- /O2 should not omit leaf frame pointer: this matches MSVC x86-32. (/Oy- is a no-op on MSVC x86-64.)
and:
when CC1 option -mdisable-fp-elim if absent, -momit-leaf-frame-pointer can also be omitted.
The new behavior matches GCC:
-fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer loses out to -momit-leaf-frame-pointer
The behavior makes lots of sense. We have 4 states:
- 00) leaf retained, non-leaf retained
- 01) leaf retained, non-leaf omitted (this is invalid)
- 10) leaf omitted, non-leaf retained (what -momit-leaf-frame-pointer was designed for)
- 11) leaf omitted, non-leaf omitted
"omit" options taking precedence over "no-omit" options is the only way
to make 3 valid states representable with -f(no-)?omit-frame-pointer and
-m(no-)?omit-leaf-pointer.
It looks better if frame_pointer is represented using tri-state. Something like this?
It would be great to have comments for conditions that are not obvious such as the overriding rules.
// There are three states for frame_pointer. enum class FpFlag {true, false, none}; FpFlag FPF = FpFlag::none; if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, options::OPT_fno_omit_frame_pointer)) FPF = A->getOption().matches(options::OPT_fno_omit_frame_pointer)) ? FpFlag::true : FpFlag::false; if (!mustUseNonLeaf && FPF == FpFlag::false) return FramePointerKind::None; if (mustUseNonLeaf || FPF == FpFlag::true || Args.hasArg(options::OPT_pg) || useFramePointerForTargetByDefault(Args, Triple)) { if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU())) return FramePointerKind::NonLeaf; return FramePointerKind::All; } return FramePointerKind::None;