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

[GISel][RISCV] Implement selectShiftMask. #77572

Merged
merged 3 commits into from
Jan 17, 2024
Merged

Conversation

mgudim
Copy link
Contributor

@mgudim mgudim commented Jan 10, 2024

Implement selectShiftMask in GlobalISel.

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 10, 2024

@llvm/pr-subscribers-backend-risc-v

Author: Mikhail Gudim (mgudim)

Changes

This is WIP, just posting it to let others know that I'm working on it.


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

2 Files Affected:

  • (modified) llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp (+49-3)
  • (added) llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir (+54)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 61bdbfc47d947f..82860eb4b9e134 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -159,9 +159,55 @@ RISCVInstructionSelector::RISCVInstructionSelector(
 
 InstructionSelector::ComplexRendererFns
 RISCVInstructionSelector::selectShiftMask(MachineOperand &Root) const {
-  // TODO: Also check if we are seeing the result of an AND operation which
-  // could be bypassed since we only check the lower log2(xlen) bits.
-  return {{[=](MachineInstrBuilder &MIB) { MIB.add(Root); }}};
+  // TODO: ShiftWidth can be 64.
+  unsigned ShiftWidth = 32;
+
+  using namespace llvm::MIPatternMatch;
+  MachineFunction &MF = *Root.getParent()->getParent()->getParent();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+
+  if (!Root.isReg())
+    return std::nullopt;
+  Register RootReg = Root.getReg();
+  Register ShAmtReg = RootReg;
+  // Peek through zext.
+  Register ZExtSrcReg;
+  if (mi_match(ShAmtReg, MRI, m_GZExt(m_Reg(ZExtSrcReg)))) {
+    ShAmtReg = ZExtSrcReg;
+  }
+
+  APInt AndMask;
+  Register AndSrcReg;
+  if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) {
+    APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
+    if (ShMask.isSubsetOf(AndMask)) {
+      ShAmtReg = AndSrcReg;
+    } else {
+      // TODO:
+      // SimplifyDemandedBits may have optimized the mask so try restoring any
+      // bits that are known zero.
+    }
+  }
+
+  APInt Imm;
+  Register Reg;
+  if (mi_match(ShAmtReg, MRI, m_GAdd(m_Reg(Reg), m_ICst(Imm)))) {
+    if (Imm != 0 && Imm.urem(ShiftWidth) == 0)
+      // If we are shifting by X+N where N == 0 mod Size, then just shift by X
+      // to avoid the ADD.
+      ShAmtReg = Reg;
+  } else if (mi_match(ShAmtReg, MRI, m_GSub(m_ICst(Imm), m_Reg(Reg)))) {
+    if (Imm != 0 && Imm.urem(ShiftWidth) == 0) {
+      // If we are shifting by N-X where N == 0 mod Size, then just shift by -X
+      // to generate a NEG instead of a SUB of a constant.
+      ShAmtReg = Reg;
+    }
+  }
+
+  if (ShAmtReg == RootReg)
+    return std::nullopt;
+
+  return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
 }
 
 InstructionSelector::ComplexRendererFns
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir
new file mode 100644
index 00000000000000..4e07819cb4b4c0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir
@@ -0,0 +1,54 @@
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select \
+# RUN:   -simplify-mir -verify-machineinstrs %s -o -
+
+#---
+#name:            shl_zext
+#legalized:       true
+#regBankSelected: true
+#tracksRegLiveness: true
+#body:             |
+#  bb.0:
+#    liveins: $x10
+#
+#    %0:gprb(s64) = COPY $x10
+#    %1:gprb(s32) = G_CONSTANT i32 1
+#    %2:gprb(s64) = G_ZEXT %1
+#    %3:gprb(s64) = G_SHL %0, %2(s64)
+#    $x10 = COPY %3(s64)
+#    PseudoRET implicit $x10
+
+#---
+#name:            shl_and
+#legalized:       true
+#regBankSelected: true
+#tracksRegLiveness: true
+#body:             |
+#  bb.0:
+#    liveins: $x10, $x11
+#
+#    %0:gprb(s64) = COPY $x10
+#    %1:gprb(s64) = COPY $x11
+#    %2:gprb(s64) = G_CONSTANT i64 31
+#    %3:gprb(s64) = G_AND %1, %2
+#    %4:gprb(s64) = G_SHL %0, %3(s64)
+#    $x10 = COPY %4(s64)
+#    PseudoRET implicit $x10
+
+---
+name:            shl_and_zext
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+
+    %0:gprb(s64) = COPY $x10
+    %addr:gprb(p0) = COPY $x11
+    %1:gprb(s32) = G_LOAD %addr(p0) :: (load (s8))
+    %2:gprb(s32) = G_CONSTANT i32 31
+    %3:gprb(s32) = G_AND %1, %2
+    %4:gprb(s64) = G_ZEXT %3
+    %5:gprb(s64) = G_SHL %0, %4(s64)
+    $x10 = COPY %5(s64)
+    PseudoRET implicit $x10

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 10, 2024

@llvm/pr-subscribers-llvm-globalisel

Author: Mikhail Gudim (mgudim)

Changes

This is WIP, just posting it to let others know that I'm working on it.


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

2 Files Affected:

  • (modified) llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp (+49-3)
  • (added) llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir (+54)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 61bdbfc47d947f..82860eb4b9e134 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -159,9 +159,55 @@ RISCVInstructionSelector::RISCVInstructionSelector(
 
 InstructionSelector::ComplexRendererFns
 RISCVInstructionSelector::selectShiftMask(MachineOperand &Root) const {
-  // TODO: Also check if we are seeing the result of an AND operation which
-  // could be bypassed since we only check the lower log2(xlen) bits.
-  return {{[=](MachineInstrBuilder &MIB) { MIB.add(Root); }}};
+  // TODO: ShiftWidth can be 64.
+  unsigned ShiftWidth = 32;
+
+  using namespace llvm::MIPatternMatch;
+  MachineFunction &MF = *Root.getParent()->getParent()->getParent();
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+
+  if (!Root.isReg())
+    return std::nullopt;
+  Register RootReg = Root.getReg();
+  Register ShAmtReg = RootReg;
+  // Peek through zext.
+  Register ZExtSrcReg;
+  if (mi_match(ShAmtReg, MRI, m_GZExt(m_Reg(ZExtSrcReg)))) {
+    ShAmtReg = ZExtSrcReg;
+  }
+
+  APInt AndMask;
+  Register AndSrcReg;
+  if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) {
+    APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
+    if (ShMask.isSubsetOf(AndMask)) {
+      ShAmtReg = AndSrcReg;
+    } else {
+      // TODO:
+      // SimplifyDemandedBits may have optimized the mask so try restoring any
+      // bits that are known zero.
+    }
+  }
+
+  APInt Imm;
+  Register Reg;
+  if (mi_match(ShAmtReg, MRI, m_GAdd(m_Reg(Reg), m_ICst(Imm)))) {
+    if (Imm != 0 && Imm.urem(ShiftWidth) == 0)
+      // If we are shifting by X+N where N == 0 mod Size, then just shift by X
+      // to avoid the ADD.
+      ShAmtReg = Reg;
+  } else if (mi_match(ShAmtReg, MRI, m_GSub(m_ICst(Imm), m_Reg(Reg)))) {
+    if (Imm != 0 && Imm.urem(ShiftWidth) == 0) {
+      // If we are shifting by N-X where N == 0 mod Size, then just shift by -X
+      // to generate a NEG instead of a SUB of a constant.
+      ShAmtReg = Reg;
+    }
+  }
+
+  if (ShAmtReg == RootReg)
+    return std::nullopt;
+
+  return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
 }
 
 InstructionSelector::ComplexRendererFns
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir
new file mode 100644
index 00000000000000..4e07819cb4b4c0
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv64.mir
@@ -0,0 +1,54 @@
+# RUN: llc -mtriple=riscv64 -run-pass=instruction-select \
+# RUN:   -simplify-mir -verify-machineinstrs %s -o -
+
+#---
+#name:            shl_zext
+#legalized:       true
+#regBankSelected: true
+#tracksRegLiveness: true
+#body:             |
+#  bb.0:
+#    liveins: $x10
+#
+#    %0:gprb(s64) = COPY $x10
+#    %1:gprb(s32) = G_CONSTANT i32 1
+#    %2:gprb(s64) = G_ZEXT %1
+#    %3:gprb(s64) = G_SHL %0, %2(s64)
+#    $x10 = COPY %3(s64)
+#    PseudoRET implicit $x10
+
+#---
+#name:            shl_and
+#legalized:       true
+#regBankSelected: true
+#tracksRegLiveness: true
+#body:             |
+#  bb.0:
+#    liveins: $x10, $x11
+#
+#    %0:gprb(s64) = COPY $x10
+#    %1:gprb(s64) = COPY $x11
+#    %2:gprb(s64) = G_CONSTANT i64 31
+#    %3:gprb(s64) = G_AND %1, %2
+#    %4:gprb(s64) = G_SHL %0, %3(s64)
+#    $x10 = COPY %4(s64)
+#    PseudoRET implicit $x10
+
+---
+name:            shl_and_zext
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+
+    %0:gprb(s64) = COPY $x10
+    %addr:gprb(p0) = COPY $x11
+    %1:gprb(s32) = G_LOAD %addr(p0) :: (load (s8))
+    %2:gprb(s32) = G_CONSTANT i32 31
+    %3:gprb(s32) = G_AND %1, %2
+    %4:gprb(s64) = G_ZEXT %3
+    %5:gprb(s64) = G_SHL %0, %4(s64)
+    $x10 = COPY %5(s64)
+    PseudoRET implicit $x10

unsigned ShiftWidth = 32;

using namespace llvm::MIPatternMatch;
MachineFunction &MF = *Root.getParent()->getParent()->getParent();
Copy link
Contributor

Choose a reason for hiding this comment

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

This should already be available in the base class

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this, thanks.

Copy link

github-actions bot commented Jan 11, 2024

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

@mgudim mgudim changed the title [WIP][GISel][RISCV] Implement selectShiftMask. [GISel][RISCV] Implement selectShiftMask. Jan 11, 2024
Implement the selectShiftMask for GlobalISel.
MIB.addReg(ShAmtReg);
}}};
}
if ((Imm.urem(ShiftWidth) & (ShiftWidth - 1)) == ShiftWidth - 1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I generalized this slightly from the non-global ISel version so that it works with negative numbers. This simplification works as long as lower 4 or 5 bits of the remainer are all 1. I think this is right, please correct me if I am wrong.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why doesn't the isel version work with negative numbers?

The & (ShiftWidth - 1) seems unnecessary. Imm.urem(ShiftWidth) should return a number in the range [0, ShiftWidth -1] so the & should have no effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you're right. I forgot that Imm is treated as unsigned.

@mgudim
Copy link
Contributor Author

mgudim commented Jan 17, 2024

This is ready for review @topperc

if (ShMask.isSubsetOf(AndMask)) {
ShAmtReg = AndSrcReg;
} else {
// TODO:
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the TODO?

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's done. Forgot to delete this line, thanks

if (Imm != 0 && Imm.urem(ShiftWidth) == 0) {
// If we are shifting by N-X where N == 0 mod Size, then just shift by -X
// to generate a NEG instead of a SUB of a constant.
ShAmtReg = MRI.createGenericVirtualRegister(ShiftLLT);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if this should be MRI.createVirtualRegister(&RISCV::GPRRegClass).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm... Not sure, I just followed similar code (like selectSHXADDOp). The docs say about target's InstructionSelector that " It is also responsible for doing the necessary constraining of gvregs into the appropriate register classes as well as passing through COPY instructions to the register allocator." So, to me it also seems more appropriate to use createVirtualRegister. We still see gpr in the output.

Copy link
Contributor

Choose a reason for hiding this comment

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

You should avoid creating new generic register during selection. You can get away with it if later steps end up constraining the register, but it's just adding extra steps

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for clarifying @arsenm I changed it here, I can change it in other places in separate MR

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

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

LGTM

@mgudim mgudim merged commit c1f4338 into llvm:main Jan 17, 2024
4 checks passed
ampandey-1995 pushed a commit to ampandey-1995/llvm-project that referenced this pull request Jan 19, 2024
Implement `selectShiftMask` in `GlobalISel`.
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.

None yet

4 participants