This is an archive of the discontinued LLVM Phabricator instance.

[mips] Add -mfix4300 flag to enable vr4300 mulmul bugfix pass
ClosedPublic

Authored by Random06457 on Dec 23 2021, 1:48 PM.

Details

Summary

Early revisions of the VR4300 have a hardware bug where two consecutive multiplications can produce an incorrect result in the second multiply.
This revision adds the -mfix4300 flag to llvm (and clang) which, when passed, provides a software fix for this issue.

More precise description of the "mulmul" bug:

1: mul.[s,d] fd,fs,ft
2: mul.[s,d] fd,fs,ft  or  [D]MULT[U] rs,rt

When the above sequence is executed by the CPU, if at least one of the source operands of the first mul instruction happens to be sNaN, 0 or Infinity, then the second mul instruction may produce an incorrect result.
This can happen both if the two mul instructions are next to each other and if the first one is in a delay slot and the second is the first instruction of the branch target.

Description of the fix:
This fix adds a backend pass to llvm which scans for mul instructions in each basic block and inserts a nop whenever the following conditions are met:

  • The current instruction is a single or double-precision floating-point mul instruction.
  • The next instruction is either a mul instruction (any kind) or a branch instruction.

Note:
I chose -mfix4300 as a name for the flag to follow the GCC nomenclature but I don't know if this is a good name.

Diff Detail

Event Timeline

Random06457 created this revision.Dec 23 2021, 1:48 PM
Random06457 requested review of this revision.Dec 23 2021, 1:48 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptDec 23 2021, 1:48 PM
Random06457 edited the summary of this revision. (Show Details)Dec 23 2021, 2:59 PM
atanasyan requested changes to this revision.Dec 24 2021, 10:13 AM

Thanks for the patch. Some notes are below.

llvm/lib/Target/Mips/MipsMulMulBugPass.cpp
17

We can move this option to the MipsTargetMachine.cpp and just do not add the pass when it is not necessary.

20

Put this class into an anonymous namespace to reduce work for a linker.

32

Let's rename the function to the fixMulMulBB and move it to the private section of the class.

37

I do not think it's a good idea to save MipsInstrInfo into the static field. AFAIK now passes cannot be run in parallel. But if that changes in the future we get a problem with the static field. As to me I would get a reference to the MipsInstrInfo in the runOnMachineFunction and pass this reference to the FixMulMulBB as a parameter.

38

Do you really need to keep a pointer to the Subtarget in the object?

49–50

These lines can be merged into the single one:

MipsII = MF.getSubtarget<MipsSubtarget>().getInstrInfo();
53–56

This code can be made a bit more compact:

for (auto &MBB: MF)
  Modified |= FixMulMulBB(MBB);
61

This function does not work with null pointer so change the argument's type to a reference.

74

Ditto

96–104

std::next call and the iterator incrementation are cheap calls. So we can write the loop in a more idiomatic form:

for (MachineBasicBlock::instr_iterator MII = MBB.instr_begin(),
                                       E = MBB.instr_end();
     MII != E; ++MII) {
  MachineBasicBlock::instr_iterator NextMII = std::next(MII);
...
111

You do not need a new MBB variable. Use MBB passed as an argument to the FixMulMulBB.

This revision now requires changes to proceed.Dec 24 2021, 10:13 AM

Addressed the comments.
I also updated isFirstMul to exclude integer multiplications which do not produce the bug. That change made me fix the tests too.

atanasyan accepted this revision.Dec 31 2021, 5:00 AM

LGTM. Thanks for the patch.

This revision is now accepted and ready to land.Dec 31 2021, 5:00 AM
This revision was landed with ongoing or failed builds.Dec 31 2021, 5:01 AM
This revision was automatically updated to reflect the committed changes.