Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIPS]: Rework atomic max/min expand for subword #89575

Merged
merged 1 commit into from
Apr 22, 2024

Conversation

wzssyqa
Copy link
Contributor

@wzssyqa wzssyqa commented Apr 22, 2024

The current code is so buggy: it can work for few cases. The problems include:

  1. ll/sc works on a whole word, while other parts other than we rmw are dropped.
  2. The oprands are not well zero-extended for unsigned ops.
  3. It doesn't work for big-endian, as the postion of subword differs with little endian.

And in fact, we can set the return value correct in ll/sc scope, so we can skip the sinkMBB.

@wzssyqa
Copy link
Contributor Author

wzssyqa commented Apr 22, 2024

See also the talk in: #89246

@wzssyqa
Copy link
Contributor Author

wzssyqa commented Apr 22, 2024

How to test:

./bin/clang --target=mips-linux-gnu -O2 -mips32r2 max.c ../llvm/test/CodeGen/Mips/atomic-min-max.ll -g -static && ./a.out

max.c.gz

Copy link

github-actions bot commented Apr 22, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@wzssyqa
Copy link
Contributor Author

wzssyqa commented Apr 22, 2024

Thanks for @jdmitrovic-syrmia find this problem.

The current code is so buggy: it can work for few cases.
The problems include:
  1. ll/sc works on a whole word, while other parts other than we rmw
     are dropped.
  2. The oprands are not well zero-extended for unsigned ops.
  3. It doesn't work for big-endian, as the postion of subword differs
     with little endian.
@yingopq
Copy link
Contributor

yingopq commented Apr 23, 2024

@wzssyqa Why are there still two cases for unsigned? I don’t quite understand. Thanks!

.addImm(ShiftImm);
BuildMI(loopMBB, DL, TII->get(SROp), StoreVal)
.addReg(StoreVal, RegState::Kill)
.addImm(ShiftImm);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yingopq You talked about here?
Note: the unsigned of SLTU is about word-size. Here we use it to compare subword.
If we use it to compare signed subword, we need to be sure that the value is sign-extend.
If we use it to compare unsigned subword, we need to be sure that the value is zero-extend.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why unsigned have else if and else cases with STI->hasMips32r2()?

Copy link
Contributor Author

@wzssyqa wzssyqa Apr 23, 2024

Choose a reason for hiding this comment

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

You are right. ANDi is available for all ISA revisions.
So we can

if (IsUnsigned)
   ANDi
else if (STI->hasMips32r2())
   SEH/SEB
else
   SLL
   SRA

So that we can save an INSN for Unsigned+pre-R2.
Can you file a new PR for it?

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, I submit and thank you for helping to solve this problem and explaining it carefully.

Choose a reason for hiding this comment

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

One question: is it valid to specify RegState::Kill when this isn't the last usage of the register StoreVal?

}
BuildMI(loopMBB, DL, TII->get(Mips::SRAV), StoreVal)
.addReg(OldVal)
.addReg(ShiftAmnt);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: ShiftAmnt may be zero. In this case, the high-part of OldVal will be keeped.
If we use that value to compare, we will get wrong result.

.addImm(ShiftImm);
BuildMI(loopMBB, DL, TII->get(SROp), StoreVal)
.addReg(StoreVal, RegState::Kill)
.addImm(ShiftImm);

Choose a reason for hiding this comment

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

One question: is it valid to specify RegState::Kill when this isn't the last usage of the register StoreVal?

.addReg(OldVal)
.addReg(ShiftAmnt);
BuildMI(loopMBB, DL, TII->get(Mips::SRAV), Incr)
.addReg(Incr)

Choose a reason for hiding this comment

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

I have noticed that sign-extension of Incr subword is removed. Why is that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For RegState::Kill, I noticed that it is also used when dest reg is same with one of src regs, not only in MIPS code.
In fact I am not sure about its really meanings.

Incr is an argument of this function passed by register $5. We can assume that it has been well sign-/zero- extended.

Copy link
Contributor

Choose a reason for hiding this comment

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

@wzssyqa Do I need to remove the RegState::Kill of StoreVal? The current test has not found any problems related to this. But I once encountered a problem related to RegState::Kill when I create a new reg like Scratch in function MachineBasicBlock *MipsTargetLowering::emitAtomicBinaryPartword and use it in function bool MipsExpandPseudo::expandAtomicBinOpSubword to replace OldVal, and when the code is executed to slt, an error is reported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems it's safe to use RegState::Kill for something like a <- op(a).
I guess it is even more friendly to register allocator, Since the register allocator can even use different hardware register for before/after this RegState::Kill note.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, now it is OK for a <- op(a), the scenario where my lab error reported is b <- op(a, RegState::Kill) + op(a).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants