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

[AArch64] Drop poison-generating flags in genSubAdd2SubSub combiner #90028

Conversation

antoniofrighetto
Copy link
Contributor

A miscompilation issue has been addressed with improved handling.

Fixes: #88950.

@llvmbot
Copy link
Collaborator

llvmbot commented Apr 25, 2024

@llvm/pr-subscribers-backend-aarch64

Author: Antonio Frighetto (antoniofrighetto)

Changes

A miscompilation issue has been addressed with improved handling.

Fixes: #88950.


Full diff: https://github.com/llvm/llvm-project/pull/90028.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.cpp (+10-2)
  • (modified) llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir (+27)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 7bf06e71a03059..8653f621ba545f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -6924,14 +6924,22 @@ genSubAdd2SubSub(MachineFunction &MF, MachineRegisterInfo &MRI,
     assert((Opcode == AArch64::SUBWrr || Opcode == AArch64::SUBXrr) &&
            "Unexpected instruction opcode.");
 
+  uint32_t RootFlags = Root.getFlags();
+  if (RootFlags & MachineInstr::NoSWrap)
+    Root.clearFlag(MachineInstr::NoSWrap);
+  if (RootFlags & MachineInstr::NoUWrap)
+    Root.clearFlag(MachineInstr::NoUWrap);
+
   MachineInstrBuilder MIB1 =
       BuildMI(MF, MIMetadata(Root), TII->get(Opcode), NewVR)
           .addReg(RegA, getKillRegState(RegAIsKill))
-          .addReg(RegB, getKillRegState(RegBIsKill));
+          .addReg(RegB, getKillRegState(RegBIsKill))
+          .setMIFlags(Root.getFlags());
   MachineInstrBuilder MIB2 =
       BuildMI(MF, MIMetadata(Root), TII->get(Opcode), ResultReg)
           .addReg(NewVR, getKillRegState(true))
-          .addReg(RegC, getKillRegState(RegCIsKill));
+          .addReg(RegC, getKillRegState(RegCIsKill))
+          .setMIFlags(Root.getFlags());
 
   InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
   InsInstrs.push_back(MIB1);
diff --git a/llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir b/llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir
index d1770bb25fae49..0b09e8a4b5cd38 100644
--- a/llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir
+++ b/llvm/test/CodeGen/AArch64/machine-combiner-subadd2.mir
@@ -237,3 +237,30 @@ body:              |
     RET_ReallyLR implicit $w0
 
 ...
+---
+# Drop nowrap flags in SUB
+
+# CHECK-LABEL: name: test8
+# CHECK:       %7:gpr64 = SUBXrr %1, %0
+# CHECK-NEXT:  %4:gpr64common = SUBXrr killed %7, killed %2
+
+name:            test8
+registers:
+  - { id: 0, class: gpr64 }
+  - { id: 1, class: gpr64 }
+  - { id: 2, class: gpr64common }
+  - { id: 3, class: gpr64 }
+  - { id: 4, class: gpr64common }
+  - { id: 5, class: gpr64 }
+body:              |
+  bb.0:
+    %1:gpr64 = COPY $x1
+    %0:gpr64 = COPY $x0
+    %2:gpr64common = ORRXri %0:gpr64, 4096
+    %3:gpr64 = ADDXrr killed %2:gpr64common, %0:gpr64
+    %4:gpr64common = nsw SUBSXrr %1:gpr64, killed %3:gpr64, implicit-def dead $nzcv
+    %5:gpr64 = SUBSXri %4:gpr64common, 0, 0, implicit-def $nzcv
+    $x0 = COPY %5:gpr64
+    RET_ReallyLR implicit $x0
+
+...

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

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

Thanks for putting the patch together.

I think the flags were being added by

uint32_t Flags = Root.getFlags();
? If this patch clears the flags on root then they will no longer be set on the new instructions, which is what we want.

It might be worth having the switch at

return as opposed to break, so that we don't run the code that is intended for mul+add. Either way this looks correct now, but it would mean that this code doesn't need to modify Root.

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp Outdated Show resolved Hide resolved
@antoniofrighetto antoniofrighetto force-pushed the feature/aarch64-combiner-drop-flags branch from 5743cbc to eb0e62a Compare April 25, 2024 15:09
@antoniofrighetto
Copy link
Contributor Author

Thanks for reviewing it!

It might be worth having the switch at

return as opposed to break, so that we don't run the code that is intended for mul+add. Either way this looks correct now, but it would mean that this code doesn't need to modify Root.

Right, although clearing the flags makes explicit the semantic of dropping flags in the combiner. I'd personally leave the break, as we would need to anticipate the following in both SUBADD_OP1/SUBADD_OP2 cases otherwise, no strong concerns though.

DelInstrs.push_back(&Root);

@v01dXYZ
Copy link

v01dXYZ commented Apr 25, 2024

@davemgreen Out of curiosity, you seem to prefer not to mutate Root if possible.

Is Root always replaced ? (it doesn't seem so but I prefer to ask).

@antoniofrighetto antoniofrighetto force-pushed the feature/aarch64-combiner-drop-flags branch from eb0e62a to 69e8cea Compare April 26, 2024 08:17
Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

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

Hi - yeah I was expecting Root to always be replaced, hence it should be correct either way. Not modifying Root feels a little cleaner though. You would not usually expect the old code to be modified as the new nodes are created, and it can be a bit confusing to follow the logic of setting the on the Root, to be used later on (in code that is easy to miss), to override the flags of the instructions that have just been created.

DelInstrs.push_back(&Root);

Yeah I was thinking that would need to be added, either to the switch or into the genSubAdd2SubSub method.

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp Outdated Show resolved Hide resolved
@antoniofrighetto antoniofrighetto force-pushed the feature/aarch64-combiner-drop-flags branch from 69e8cea to 84c6c43 Compare April 26, 2024 09:24
@antoniofrighetto
Copy link
Contributor Author

Should be on track now!

Copy link

github-actions bot commented Apr 26, 2024

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

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

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

Thanks. LGTM

A miscompilation issue has been addressed with improved handling.

Fixes: llvm#88950.
@antoniofrighetto antoniofrighetto force-pushed the feature/aarch64-combiner-drop-flags branch from 84c6c43 to 23b6709 Compare April 26, 2024 09:34
@antoniofrighetto antoniofrighetto merged commit 23b6709 into llvm:main Apr 26, 2024
3 of 4 checks passed
@momchil-velikov
Copy link
Collaborator

It looks like there's a slight issue with the test. If you have enabled expensive checks, the combiner calls verifyPatternOrder which creates(and discards) a few instructions, but in doing so consumes some virtual register numbers. Then you get unexpected output in the test, for example, I get %9 instead of %7 in these check lines:

# CHECK-LABEL: name: test8
# CHECK:       %7:gpr64 = SUBXrr %1, %0
# CHECK-NEXT:  %4:gpr64common = SUBXrr killed %7, killed %2

@antoniofrighetto
Copy link
Contributor Author

@momchil-velikov Thank you for reporting, and sorry to get back only now, somehow I missed the notification for this. Fixed in ca25702.

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

Successfully merging this pull request may close these issues.

AArch64 backend miscompilation related to sshl.sat
6 participants