Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/coreclr/jit/emitxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -758,19 +758,29 @@ bool emitter::DoesWriteSignFlag(instruction ins)
}

//------------------------------------------------------------------------
// DoesResetOverflowAndCarryFlags: check if the instruction resets the
// OF and CF flag to 0.
// DoesModifySameFlagsAsTESTInst: check if the instruction modifies
// the same flags as a "TEST" instruction, which allows some optims
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we provide more detail on what it allows, if it's not too verbose?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kg thans for the review, very appreciated 🙂
Yes sure I can add more info and point out that this allows to potentially skip a test instruction.

//
// Arguments:
// ins - instruction to test
//
// Return Value:
// true if instruction resets the OF and CF flag, false otherwise.
// true if instruction modifies the same flags as "TEST" instruction
//
bool emitter::DoesResetOverflowAndCarryFlags(instruction ins)
// Note:
// "TEST" instruction:
// - Resets OF and CF flags to zero
// - Sets SF, ZF, PF flags from the result
// - Leaves AF undefined
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure here whether it makes sense to add a condition on AF flag as well

//
bool emitter::DoesModifySameFlagsAsTESTInst(instruction ins)
{
insFlags flags = CodeGenInterface::instInfo[ins];
return (flags & (Resets_OF | Resets_CF)) == (Resets_OF | Resets_CF);
return (flags & (Resets_OF | Writes_OF)) != 0 &&
(flags & (Resets_CF | Writes_CF)) != 0 &&
(flags & (Resets_SF | Writes_SF)) != 0 &&
(flags & (Resets_ZF | Writes_ZF)) != 0 &&
(flags & (Resets_PF | Writes_PF)) != 0;
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -1457,9 +1467,7 @@ bool emitter::AreFlagsSetToZeroCmp(regNumber reg, emitAttr opSize, GenCondition

// Certain instruction like and, or and xor modifies exactly same flags
// as "test" instruction.
// They reset OF and CF to 0 and modifies SF, ZF and PF.
if (DoesResetOverflowAndCarryFlags(lastIns) && DoesWriteSignFlag(lastIns) && DoesWriteZeroFlag(lastIns) &&
DoesWriteParityFlag(lastIns))
if (DoesModifySameFlagsAsTESTInst(lastIns))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This previously checked specifically that the OF and CF were reset but now it's sufficient to write them instead of reset them, which means they might be nonzero. But this method is named AreFlagsSetToZeroCmp, so this check becomes misleading. I think OF and CF should be restricted to Resets.

Copy link
Author

@Lotendan Lotendan Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too sure what you expect here or how I could improve the code to make it more readable. Perhaps renaming DoesModify into ˋDoesUpdateˋ? Would that help? Or do you have any other suggestion/insight?
The previous code used to check for Write and not just Reset just as well.
Basically if an instruction modifies the same flags as a test instruction (be it reset or write) then we can skip a test instruction indeed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code was (flags & (Resets_OF | Resets_CF)) == (Resets_OF | Resets_CF) but now it is Resets_OF | Writes_OF and Resets_CF | Writes_CF, which is a difference. I'm not sure if it's bad though.

{
return id->idOpSize() == opSize;
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/emitxarch.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ static bool HasRegularWideImmediateForm(instruction ins);
static bool DoesWriteZeroFlag(instruction ins);
static bool DoesWriteParityFlag(instruction ins);
static bool DoesWriteSignFlag(instruction ins);
static bool DoesResetOverflowAndCarryFlags(instruction ins);
static bool DoesModifySameFlagsAsTESTInst(instruction ins);
bool IsFlagsAlwaysModified(instrDesc* id);
static bool IsRexW0Instruction(instruction ins);
static bool IsRexW1Instruction(instruction ins);
Expand Down
Loading