Skip to content

[GISel][RISCV] Implement selectShiftMask. #77572

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

Merged
merged 3 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "RISCVSubtarget.h"
#include "RISCVTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
Expand Down Expand Up @@ -159,9 +160,71 @@ 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); }}};
if (!Root.isReg())
return std::nullopt;

using namespace llvm::MIPatternMatch;
MachineRegisterInfo &MRI = MF->getRegInfo();

Register RootReg = Root.getReg();
Register ShAmtReg = RootReg;
const LLT ShiftLLT = MRI.getType(RootReg);
unsigned ShiftWidth = ShiftLLT.getSizeInBits();
assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
// 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 {
// SimplifyDemandedBits may have optimized the mask so try restoring any
// bits that are known zero.
KnownBits Known = KB->getKnownBits(ShAmtReg);
if (ShMask.isSubsetOf(AndMask | Known.Zero))
ShAmtReg = AndSrcReg;
}
}

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 = MRI.createVirtualRegister(&RISCV::GPRRegClass);
unsigned NegOpc = Subtarget->is64Bit() ? RISCV::SUBW : RISCV::SUB;
return {{[=](MachineInstrBuilder &MIB) {
MachineIRBuilder(*MIB.getInstr())
.buildInstr(NegOpc, {ShAmtReg}, {Register(RISCV::X0), Reg});
MIB.addReg(ShAmtReg);
}}};
}
if (Imm.urem(ShiftWidth) == ShiftWidth - 1) {
// If we are shifting by N-X where N == -1 mod Size, then just shift by ~X
// to generate a NOT instead of a SUB of a constant.
ShAmtReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);
return {{[=](MachineInstrBuilder &MIB) {
MachineIRBuilder(*MIB.getInstr())
.buildInstr(RISCV::XORI, {ShAmtReg}, {Reg})
.addImm(-1);
MIB.addReg(ShAmtReg);
}}};
}
}

return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
}

InstructionSelector::ComplexRendererFns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY1]], 32
; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 32
; CHECK-NEXT: [[ROLW:%[0-9]+]]:gpr = ROLW [[COPY]], [[SRLI]]
; CHECK-NEXT: [[ROLW:%[0-9]+]]:gpr = ROLW [[COPY]], [[COPY1]]
; CHECK-NEXT: $x10 = COPY [[ROLW]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s64) = COPY $x10
Expand Down Expand Up @@ -71,9 +69,7 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SLLI:%[0-9]+]]:gpr = SLLI [[COPY1]], 32
; CHECK-NEXT: [[SRLI:%[0-9]+]]:gpr = SRLI [[SLLI]], 32
; CHECK-NEXT: [[RORW:%[0-9]+]]:gpr = RORW [[COPY]], [[SRLI]]
; CHECK-NEXT: [[RORW:%[0-9]+]]:gpr = RORW [[COPY]], [[COPY1]]
; CHECK-NEXT: $x10 = COPY [[RORW]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s64) = COPY $x10
Expand Down
190 changes: 190 additions & 0 deletions llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/shift-rv32.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
# RUN: llc -mtriple=riscv32 -run-pass=instruction-select \
# RUN: -simplify-mir -verify-machineinstrs %s -o - | FileCheck %s

# This 32-bit version doesn't have tests for zext, because there is no legal type to zext from.
---
name: shl
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[COPY1]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%3:gprb(s32) = G_SHL %0, %1
$x10 = COPY %3(s32)
PseudoRET implicit $x10
...

---
name: shl_and
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_and
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[COPY1]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 31
%3:gprb(s32) = G_AND %1, %2
%4:gprb(s32) = G_SHL %0, %3(s32)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...

---
name: shl_and_with_simplified_mask
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_and_with_simplified_mask
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[ANDI:%[0-9]+]]:gpr = ANDI [[COPY1]], 31
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[ANDI]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 31
%3:gprb(s32) = G_AND %1, %2
%4:gprb(s32) = G_CONSTANT i32 31
%5:gprb(s32) = G_AND %3, %4
%6:gprb(s32) = G_SHL %0, %5(s32)
$x10 = COPY %6(s32)
PseudoRET implicit $x10
...

---
name: shl_add
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_add
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[COPY1]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 32
%3:gprb(s32) = G_ADD %1, %2
%4:gprb(s32) = G_SHL %0, %3(s32)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...

---
name: shl_sub
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_sub
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[SUB:%[0-9]+]]:gpr = SUB $x0, [[COPY1]]
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[SUB]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 32
%3:gprb(s32) = G_SUB %2, %1
%4:gprb(s32) = G_SHL %0, %3(s32)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...

---
name: shl_bitwise_not
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_bitwise_not
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[XORI:%[0-9]+]]:gpr = XORI [[COPY1]], -1
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[XORI]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 -1
%3:gprb(s32) = G_SUB %2, %1
%4:gprb(s32) = G_SHL %0, %3(s32)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...

---
name: shl_bitwise_not_2
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x10, $x11

; CHECK-LABEL: name: shl_bitwise_not_2
; CHECK: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
; CHECK-NEXT: [[XORI:%[0-9]+]]:gpr = XORI [[COPY1]], -1
; CHECK-NEXT: [[SLL:%[0-9]+]]:gpr = SLL [[COPY]], [[XORI]]
; CHECK-NEXT: $x10 = COPY [[SLL]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:gprb(s32) = COPY $x10
%1:gprb(s32) = COPY $x11
%2:gprb(s32) = G_CONSTANT i32 31
%3:gprb(s32) = G_SUB %2, %1
%4:gprb(s32) = G_SHL %0, %3(s32)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...
Loading