Skip to content

[RISCV][GISEL] legalize, regbankselect, and instruction-select for G_… #73061

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 6 commits into from
Nov 30, 2023
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
53 changes: 53 additions & 0 deletions llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class RISCVInstructionSelector : public InstructionSelector {
const TargetRegisterClass *
getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;

bool isRegInGprb(Register Reg, MachineRegisterInfo &MRI) const;
bool isRegInFprb(Register Reg, MachineRegisterInfo &MRI) const;

// tblgen-erated 'select' implementation, used as the initial selector for
// the patterns that don't require complex C++.
bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
Expand Down Expand Up @@ -77,6 +80,10 @@ class RISCVInstructionSelector : public InstructionSelector {
MachineRegisterInfo &MRI) const;
void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
MachineIRBuilder &MIB) const;
bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) const;
bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) const;

ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
Expand Down Expand Up @@ -627,11 +634,47 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
}
case TargetOpcode::G_IMPLICIT_DEF:
return selectImplicitDef(MI, MIB, MRI);
case TargetOpcode::G_MERGE_VALUES:
return selectMergeValues(MI, MIB, MRI);
case TargetOpcode::G_UNMERGE_VALUES:
return selectUnmergeValues(MI, MIB, MRI);
default:
return false;
}
}

bool RISCVInstructionSelector::selectMergeValues(
MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
assert(MI.getOpcode() == TargetOpcode::G_MERGE_VALUES);

// Build a F64 Pair from operands
if (MI.getNumOperands() != 3)
return false;
Register Dst = MI.getOperand(0).getReg();
Register Lo = MI.getOperand(1).getReg();
Register Hi = MI.getOperand(2).getReg();
if (!isRegInFprb(Dst, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
return false;
MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo));
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
}

bool RISCVInstructionSelector::selectUnmergeValues(
MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);

// Split F64 Src into two s32 parts
if (MI.getNumOperands() != 3)
return false;
Register Src = MI.getOperand(2).getReg();
Register Lo = MI.getOperand(0).getReg();
Register Hi = MI.getOperand(1).getReg();
if (!isRegInFprb(Src, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
return false;
MI.setDesc(TII.get(RISCV::SplitF64Pseudo));
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
}

bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,
MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) {
Expand Down Expand Up @@ -715,6 +758,16 @@ const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
return nullptr;
}

bool RISCVInstructionSelector::isRegInGprb(Register Reg,
MachineRegisterInfo &MRI) const {
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::GPRBRegBankID;
}

bool RISCVInstructionSelector::isRegInFprb(Register Reg,
MachineRegisterInfo &MRI) const {
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::FPRBRegBankID;
}

bool RISCVInstructionSelector::selectCopy(MachineInstr &MI,
MachineRegisterInfo &MRI) const {
Register DstReg = MI.getOperand(0).getReg();
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,13 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
getActionDefinitionsBuilder(Op)
.widenScalarToNextPow2(LitTyIdx, XLen)
auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
if (XLen == 32 && ST.hasStdExtD()) {
LLT IdxZeroTy = G_MERGE_VALUES ? s64 : s32;
LLT IdxOneTy = G_MERGE_VALUES ? s32 : s64;
MergeUnmergeActions.legalFor({IdxZeroTy, IdxOneTy});
}
MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
.widenScalarToNextPow2(BigTyIdx, XLen)
.clampScalar(LitTyIdx, sXLen, sXLen)
.clampScalar(BigTyIdx, sXLen, sXLen);
Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,28 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
break;
}
case TargetOpcode::G_MERGE_VALUES: {
// Use FPR64 for s64 merge on rv32.
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
OpdsMapping[1] = GPRValueMapping;
OpdsMapping[2] = GPRValueMapping;
}
break;
}
case TargetOpcode::G_UNMERGE_VALUES: {
// Use FPR64 for s64 unmerge on rv32.
LLT Ty = MRI.getType(MI.getOperand(2).getReg());
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
OpdsMapping[0] = GPRValueMapping;
OpdsMapping[1] = GPRValueMapping;
OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
}
break;
}
default:
// By default map all scalars to GPR.
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=instruction-select \
# RUN: -simplify-mir -verify-machineinstrs %s -o - | FileCheck %s

---
name: merge_i64
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0.entry:
liveins: $x10
; CHECK-LABEL: name: merge_i64
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
; CHECK-NEXT: [[BuildPairF64Pseudo:%[0-9]+]]:fpr64 = BuildPairF64Pseudo [[COPY]], [[COPY]]
; CHECK-NEXT: $f10_d = COPY [[BuildPairF64Pseudo]]
; CHECK-NEXT: PseudoRET implicit $f10_d
%0:gprb(s32) = COPY $x10
%1:fprb(s64) = G_MERGE_VALUES %0(s32), %0(s32)
$f10_d = COPY %1(s64)
PseudoRET implicit $f10_d
...
---
name: unmerge_i32
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0.entry:
liveins: $f10_d
; CHECK-LABEL: name: unmerge_i32
; CHECK: liveins: $f10_d
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
; CHECK-NEXT: [[SplitF64Pseudo:%[0-9]+]]:gpr, [[SplitF64Pseudo1:%[0-9]+]]:gpr = SplitF64Pseudo [[COPY]]
; CHECK-NEXT: $x10 = COPY [[SplitF64Pseudo]]
; CHECK-NEXT: PseudoRET implicit $x10
%0:fprb(s64) = COPY $f10_d
%1:gprb(s32), %2:gprb(s32) = G_UNMERGE_VALUES %0(s64)
$x10 = COPY %1(s32)
PseudoRET implicit $x10
...
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
; RUN: llc -mtriple=riscv32 -global-isel -mattr=+d -stop-after=legalizer -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=CHECK %s

define i64 @double_to_i64(double %a) {
; CHECK-LABEL: name: double_to_i64
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $f10_d
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
; CHECK-NEXT: $x10 = COPY [[UV]](s32)
; CHECK-NEXT: $x11 = COPY [[UV1]](s32)
; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
%1 = bitcast double %a to i64
ret i64 %1
}

define double @i64_to_double(i64 %a) {
; CHECK-LABEL: name: i64_to_double
; CHECK: bb.1 (%ir-block.0):
; CHECK-NEXT: liveins: $x10, $x11
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
; CHECK-NEXT: $f10_d = COPY [[MV]](s64)
; CHECK-NEXT: PseudoRET implicit $f10_d
%1 = bitcast i64 %a to double
ret double %1
}
131 changes: 131 additions & 0 deletions llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - \
# RUN: | FileCheck --check-prefix=RV32 %s

---
name: merge_i32
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: merge_i32
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(s32) = G_ASSERT_ZEXT [[COPY]], 16
; RV32-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
; RV32-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[ASSERT_ZEXT]], [[C]](s32)
; RV32-NEXT: [[OR:%[0-9]+]]:_(s32) = G_OR [[ASSERT_ZEXT]], [[SHL]]
; RV32-NEXT: $x10 = COPY [[OR]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s32) = G_ASSERT_ZEXT %0, 16
%2:_(s16) = G_TRUNC %1(s32)
%3:_(s32) = G_MERGE_VALUES %2(s16), %2(s16)
$x10 = COPY %3(s32)
PseudoRET implicit $x10
...
---
name: merge_i64
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: merge_i64
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s64) = G_MERGE_VALUES %0(s32), %0(s32)
%2:_(s32) = G_TRUNC %1(s64)
$x10 = COPY %2(s32)
PseudoRET implicit $x10
...
---
name: merge_i128
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: merge_i128
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%1:_(s32) = COPY $x10
%2:_(s64) = G_ZEXT %1(s32)
%0:_(s128) = G_MERGE_VALUES %2(s64), %2(s64)
%3:_(s32) = G_TRUNC %0(s128)
$x10 = COPY %3(s32)
PseudoRET implicit $x10
...
---
name: unmerge_i32
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: unmerge_i32
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s64) = G_ZEXT %0(s32)
%2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64)
$x10 = COPY %2(s32)
PseudoRET implicit $x10
...
---
name: unmerge_i64
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: unmerge_i64
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s64) = G_ZEXT %0(s32)
%2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64)
$x10 = COPY %2(s32)
PseudoRET implicit $x10
...
---
name: unmerge_i128
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: unmerge_i128
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
; RV32-NEXT: $x10 = COPY [[C]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s128) = G_ZEXT %0(s32)
%2:_(s64), %3:_(s64) = G_UNMERGE_VALUES %1(s128)
%4:_(s32) = G_TRUNC %3(s64)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...
---
name: unmerge_i256
body: |
bb.0.entry:
liveins: $x10
; RV32-LABEL: name: unmerge_i256
; RV32: liveins: $x10
; RV32-NEXT: {{ $}}
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
; RV32-NEXT: PseudoRET implicit $x10
%0:_(s32) = COPY $x10
%1:_(s256) = G_ZEXT %0(s32)
%2:_(s128), %3:_(s128) = G_UNMERGE_VALUES %1(s256)
%4:_(s32) = G_TRUNC %2(s128)
$x10 = COPY %4(s32)
PseudoRET implicit $x10
...
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=legalizer %s -o - \
# RUN: | FileCheck %s

---
name: merge_i64
body: |
bb.0.entry:
liveins: $x10
; CHECK-LABEL: name: merge_i64
; CHECK: liveins: $x10
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY]](s32)
; CHECK-NEXT: $f10_d = COPY [[MV]](s64)
; CHECK-NEXT: PseudoRET implicit $f10_d
%0:_(s32) = COPY $x10
%1:_(s64) = G_MERGE_VALUES %0(s32), %0(s32)
$f10_d = COPY %1(s64)
PseudoRET implicit $f10_d
...
---
name: unmerge_i32
body: |
bb.0.entry:
liveins: $f10_d
; CHECK-LABEL: name: unmerge_i32
; CHECK: liveins: $f10_d
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
; CHECK-NEXT: $x10 = COPY [[UV]](s32)
; CHECK-NEXT: PseudoRET implicit $x10
%0:_(s64) = COPY $f10_d
%1:_(s32), %2:_(s32) = G_UNMERGE_VALUES %0(s64)
$x10 = COPY %1(s32)
PseudoRET implicit $x10
...
Loading