-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
[RISCV] Add OR/XOR/SUB to RISCVInstrInfo::isCopyInstrImpl #132002
Conversation
This adds coverage for additional instructions in isCopyInstrImpl, for now picking just those where I can observe that there is a codegen difference for SPEC.
@llvm/pr-subscribers-backend-risc-v Author: Alex Bradbury (asb) ChangesThis adds coverage for additional instructions in isCopyInstrImpl, for now picking just those where I can observe that there is a codegen difference for SPEC. Implementing these removes a small number of effectively no-op instructions in a SPEC compilation. As a starting point I've just added the cases that cause a code gen difference, but welcome discussion on to what degree we want isCopyInstrImpl to be exhaustive. I would highlight:
Full diff: https://github.com/llvm/llvm-project/pull/132002.diff 2 Files Affected:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index c197f06855b6e..84e167e452130 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1660,6 +1660,8 @@ RISCVInstrInfo::isCopyInstrImpl(const MachineInstr &MI) const {
default:
break;
case RISCV::ADD:
+ case RISCV::OR:
+ case RISCV::XOR:
if (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == RISCV::X0 &&
MI.getOperand(2).isReg())
return DestSourcePair{MI.getOperand(0), MI.getOperand(2)};
@@ -1673,6 +1675,11 @@ RISCVInstrInfo::isCopyInstrImpl(const MachineInstr &MI) const {
MI.getOperand(2).getImm() == 0)
return DestSourcePair{MI.getOperand(0), MI.getOperand(1)};
break;
+ case RISCV::SUB:
+ if (MI.getOperand(2).isReg() && MI.getOperand(2).getReg() == RISCV::X0 &&
+ MI.getOperand(1).isReg())
+ return DestSourcePair{MI.getOperand(0), MI.getOperand(1)};
+ break;
case RISCV::FSGNJ_D:
case RISCV::FSGNJ_S:
case RISCV::FSGNJ_H:
diff --git a/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp b/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
index f7351f00ae282..ac802c8d33fa1 100644
--- a/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
+++ b/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
@@ -135,31 +135,50 @@ TEST_P(RISCVInstrInfoTest, IsCopyInstrImpl) {
EXPECT_EQ(MI4Res->Destination->getReg(), RISCV::F1_D);
EXPECT_EQ(MI4Res->Source->getReg(), RISCV::F2_D);
- // ADD.
- MachineInstr *MI5 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1)
- .addReg(RISCV::X2)
- .addReg(RISCV::X3)
- .getInstr();
- auto MI5Res = TII->isCopyInstrImpl(*MI5);
- EXPECT_FALSE(MI5Res.has_value());
+ // ADD/OR/XOR.
+ for (unsigned Opc : {RISCV::ADD, RISCV::OR, RISCV::XOR}) {
+ MachineInstr *MI5 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)
+ .addReg(RISCV::X2)
+ .addReg(RISCV::X3)
+ .getInstr();
+ auto MI5Res = TII->isCopyInstrImpl(*MI5);
+ EXPECT_FALSE(MI5Res.has_value());
+
+ MachineInstr *MI6 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)
+ .addReg(RISCV::X0)
+ .addReg(RISCV::X2)
+ .getInstr();
+ auto MI6Res = TII->isCopyInstrImpl(*MI6);
+ ASSERT_TRUE(MI6Res.has_value());
+ EXPECT_EQ(MI6Res->Destination->getReg(), RISCV::X1);
+ EXPECT_EQ(MI6Res->Source->getReg(), RISCV::X2);
+
+ MachineInstr *MI7 = BuildMI(*MF, DL, TII->get(Opc), RISCV::X1)
+ .addReg(RISCV::X2)
+ .addReg(RISCV::X0)
+ .getInstr();
+ auto MI7Res = TII->isCopyInstrImpl(*MI7);
+ ASSERT_TRUE(MI7Res.has_value());
+ EXPECT_EQ(MI7Res->Destination->getReg(), RISCV::X1);
+ EXPECT_EQ(MI7Res->Source->getReg(), RISCV::X2);
+ }
- MachineInstr *MI6 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1)
+ // SUB.
+ MachineInstr *MI8 = BuildMI(*MF, DL, TII->get(RISCV::SUB), RISCV::X1)
.addReg(RISCV::X0)
.addReg(RISCV::X2)
.getInstr();
- auto MI6Res = TII->isCopyInstrImpl(*MI6);
- ASSERT_TRUE(MI6Res.has_value());
- EXPECT_EQ(MI6Res->Destination->getReg(), RISCV::X1);
- EXPECT_EQ(MI6Res->Source->getReg(), RISCV::X2);
+ auto MI8Res = TII->isCopyInstrImpl(*MI8);
+ EXPECT_FALSE(MI8Res.has_value());
- MachineInstr *MI7 = BuildMI(*MF, DL, TII->get(RISCV::ADD), RISCV::X1)
+ MachineInstr *MI9 = BuildMI(*MF, DL, TII->get(RISCV::SUB), RISCV::X1)
.addReg(RISCV::X2)
.addReg(RISCV::X0)
.getInstr();
- auto MI7Res = TII->isCopyInstrImpl(*MI7);
- ASSERT_TRUE(MI7Res.has_value());
- EXPECT_EQ(MI7Res->Destination->getReg(), RISCV::X1);
- EXPECT_EQ(MI7Res->Source->getReg(), RISCV::X2);
+ auto MI9Res = TII->isCopyInstrImpl(*MI9);
+ ASSERT_TRUE(MI9Res.has_value());
+ EXPECT_EQ(MI9Res->Destination->getReg(), RISCV::X1);
+ EXPECT_EQ(MI9Res->Source->getReg(), RISCV::X2);
}
TEST_P(RISCVInstrInfoTest, GetMemOperandsWithOffsetWidth) {
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Since you mentioned rotate with zero offset, have you seen any left/right shiftings with zero offset in SPEC?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
In general, sticking to those that we can write a test case from IR (or otherwise not over reduced) for seems like a reasonable line. That's not quite the same as causing codegen differences in spec, but if we can't test something, having code seems undesirable. If we can test something, but it doesn't show up, then I'd say that's largely at the discretion of the author. (i.e. if they find the time worthwhile)
This might be a reasonable exception to the "only with high level tests" policy I suggest above. I could go either way, and am happy to defer to your judgement. |
One aside here: The need to handle all these cases hints we have a canonicalization problem. All of these should be canonicalized into a single instruction. Unless having them in the isCopyInstrImpl enables that canonicalization - I haven't checked - we might have something to follow up on. |
I explored some of the things mentioned here in review:
I'll go ahead and merge this now and follow-up on other observed oddities with PRs / issues. |
As with llvm#132002, these do show up in a compilation of llvm-test-suite (including SPEC 2007). We remove 30-40 static instances so this isn't anything earth shattering. rs2 is always added to the other shifted (and potentially extended) operand unmodified, so rs1==zero is equivalent to a copy.
The promised tracking/summary issue is up at #133449 |
As with #132002, these do show up in a compilation of llvm-test-suite (including SPEC 2017). We remove 30-40 static instances so this isn't anything earth shattering. rs2 is always added to the other shifted (and potentially extended) operand unmodified, so rs1==zero is equivalent to a copy.
This adds coverage for additional instructions in isCopyInstrImpl, for now picking just those where I can observe that there is a codegen difference for SPEC.
Implementing these removes a small number of effectively no-op instructions in a SPEC compilation. As a starting point I've just added the cases that cause a code gen difference, but welcome discussion on to what degree we want isCopyInstrImpl to be exhaustive.
I would highlight: