[llvm] [RISCV][GISEL] legalize, regbankselect, and instruction-select for G_… (PR #73061)
Michael Maitland via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 30 08:39:22 PST 2023
https://github.com/michaelmaitland updated https://github.com/llvm/llvm-project/pull/73061
>From 3ee987eb3893af029213d249490f63895905955a Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Mon, 20 Nov 2023 16:30:14 -0800
Subject: [PATCH 1/6] [RISCV][GISEL] legalize, regbankselect, and
instruction-select for G_[UN]MERGE_VALUES
When MERGE or UNMERGE s64 on a subtarget that is non-64bit, it must have
the D extension and use FPR in order to be legal.
All other instances of MERGE and UNMERGE that can be made legal should be
narrowed, widend, or replaced by the combiner.
---
.../RISCV/GISel/RISCVInstructionSelector.cpp | 59 ++++++++
.../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 4 +
.../RISCV/GISel/RISCVRegisterBankInfo.cpp | 28 ++++
.../instruction-select/merge-unmerge-rv32.mir | 44 ++++++
.../bitcast-between-f64-and-i64.ll | 31 +++++
.../GlobalISel/legalizer/merge-unmerge-d.mir | 38 +++++
.../legalizer/rv32/merge-unmerge.mir | 131 ++++++++++++++++++
.../legalizer/rv64/merge-unmerge.mir | 119 ++++++++++++++++
.../regbankselect/merge-unmerge-rv32.mir | 40 ++++++
9 files changed, 494 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/merge-unmerge-rv32.mir
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/bitcast-between-f64-and-i64.ll
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir
create mode 100644 llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/merge-unmerge-rv32.mir
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 6e5829ba93a7128..a9de87594d22055 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -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;
@@ -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;
@@ -627,11 +634,53 @@ 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;
+ MachineInstr *Result =
+ MIB.buildInstr(RISCV::BuildPairF64Pseudo, {Dst}, {Lo, Hi});
+
+ MI.eraseFromParent();
+ return constrainSelectedInstRegOperands(*Result, 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;
+ MachineInstr *Result = MIB.buildInstr(RISCV::SplitF64Pseudo, {Lo, Hi}, {Src});
+
+ MI.eraseFromParent();
+ return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI);
+}
+
bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,
MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) {
@@ -715,6 +764,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();
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index d745e0957168ce7..3ea8191d03e144c 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -86,6 +86,10 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
getActionDefinitionsBuilder(Op)
+ .legalIf([=, &ST](const LegalityQuery &Query) -> bool {
+ return ST.hasStdExtD() && typeIs(LitTyIdx, s32)(Query) &&
+ typeIs(BigTyIdx, s64)(Query);
+ })
.widenScalarToNextPow2(LitTyIdx, XLen)
.widenScalarToNextPow2(BigTyIdx, XLen)
.clampScalar(LitTyIdx, sXLen, sXLen)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 8f274f0417cac62..50cfb3dbd50fa98 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -423,6 +423,34 @@ 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.
+ assert(MI.getNumOperands() == 3 && "Unsupported G_MERGE_VALUES");
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
+ assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
+ // FIXME: OpdsMapping[0, 1] should probably visit their uses to determine
+ // if GPRValueMapping or FPRValueMapping
+ OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
+ OpdsMapping[1] = GPRValueMapping;
+ OpdsMapping[2] = GPRValueMapping;
+ }
+ break;
+ }
+ case TargetOpcode::G_UNMERGE_VALUES: {
+ // Use FPR64 for s64 unmerge on rv32.
+ assert(MI.getNumOperands() == 3 && "Unsupported G_UNMERGE_VALUES");
+ LLT Ty = MRI.getType(MI.getOperand(2).getReg());
+ if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
+ assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
+ // FIXME: OpdsMapping[0, 1] should probably visit their uses to determine
+ // if GPRValueMapping or FPRValueMapping
+ 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) {
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/merge-unmerge-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/merge-unmerge-rv32.mir
new file mode 100644
index 000000000000000..11d3bf6a4cd0e6e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/merge-unmerge-rv32.mir
@@ -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
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/bitcast-between-f64-and-i64.ll b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/bitcast-between-f64-and-i64.ll
new file mode 100644
index 000000000000000..5461f7366c523a4
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/bitcast-between-f64-and-i64.ll
@@ -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
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir
new file mode 100644
index 000000000000000..10c775cd9ecfe1a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir
@@ -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
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir
new file mode 100644
index 000000000000000..2e4a39c468111f2
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir
@@ -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
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir
new file mode 100644
index 000000000000000..3cf3a7c24863936
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir
@@ -0,0 +1,119 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv64 -run-pass=legalizer %s -o - | FileCheck %s
+
+---
+name: merge_i32
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: merge_i32
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(s64) = G_ASSERT_ZEXT [[COPY]], 16
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ASSERT_ZEXT]], [[C]](s64)
+ ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s64) = G_OR [[ASSERT_ZEXT]], [[SHL]]
+ ; CHECK-NEXT: $x10 = COPY [[OR]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s64) = G_ASSERT_ZEXT %0, 16
+ %2:_(s16) = G_TRUNC %1(s64)
+ %3:_(s32) = G_MERGE_VALUES %2(s16), %2(s16)
+ %4:_(s64) = G_ZEXT %3(s32)
+ $x10 = COPY %4(s64)
+ PseudoRET implicit $x10
+...
+---
+name: merge_i64
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: merge_i64
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(s64) = G_ASSERT_ZEXT [[COPY]], 32
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 32
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ASSERT_ZEXT]], [[C]](s64)
+ ; CHECK-NEXT: [[OR:%[0-9]+]]:_(s64) = G_OR [[ASSERT_ZEXT]], [[SHL]]
+ ; CHECK-NEXT: $x10 = COPY [[OR]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s64) = G_ASSERT_ZEXT %0, 32
+ %2:_(s32) = G_TRUNC %1(s64)
+ %3:_(s64) = G_MERGE_VALUES %2(s32), %2(s32)
+ $x10 = COPY %3(s64)
+ PseudoRET implicit $x10
+...
+---
+name: merge_i128
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: merge_i128
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: $x10 = COPY [[COPY]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s128) = G_MERGE_VALUES %0(s64), %0(s64)
+ %2:_(s64) = G_TRUNC %1(s128)
+ $x10 = COPY %2(s64)
+ PseudoRET implicit $x10
+...
+---
+name: unmerge_i32
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: unmerge_i32
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 4294967295
+ ; CHECK-NEXT: [[AND:%[0-9]+]]:_(s64) = G_AND [[COPY]], [[C]]
+ ; CHECK-NEXT: $x10 = COPY [[AND]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s32), %2:_(s32) = G_UNMERGE_VALUES %0(s64)
+ %3:_(s64) = G_ZEXT %1(s32)
+ $x10 = COPY %3(s64)
+ PseudoRET implicit $x10
+...
+---
+name: unmerge_i64
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: unmerge_i64
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: $x10 = COPY [[COPY]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s128) = G_ZEXT %0(s64)
+ %2:_(s64), %3:_(s64) = G_UNMERGE_VALUES %1(s128)
+ $x10 = COPY %2(s64)
+ PseudoRET implicit $x10
+...
+---
+name: unmerge_i128
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: unmerge_i128
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x10
+ ; CHECK-NEXT: $x10 = COPY [[COPY]](s64)
+ ; CHECK-NEXT: PseudoRET implicit $x10
+ %0:_(s64) = COPY $x10
+ %1:_(s256) = G_ZEXT %0(s64)
+ %2:_(s128), %3:_(s128) = G_UNMERGE_VALUES %1(s256)
+ %4:_(s64) = G_TRUNC %2(s128)
+ $x10 = COPY %4(s64)
+ PseudoRET implicit $x10
+...
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/merge-unmerge-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/merge-unmerge-rv32.mir
new file mode 100644
index 000000000000000..4785b86a8a78632
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/merge-unmerge-rv32.mir
@@ -0,0 +1,40 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=regbankselect %s -o - \
+# RUN: | FileCheck %s
+
+---
+name: merge_i64
+legalized: true
+body: |
+ bb.0.entry:
+ liveins: $x10
+ ; CHECK-LABEL: name: merge_i64
+ ; CHECK: liveins: $x10
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gprb(s32) = COPY $x10
+ ; CHECK-NEXT: [[MV:%[0-9]+]]:fprb(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
+legalized: true
+body: |
+ bb.0.entry:
+ liveins: $f10_d
+ ; CHECK-LABEL: name: unmerge_i32
+ ; CHECK: liveins: $f10_d
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:fprb(s64) = COPY $f10_d
+ ; CHECK-NEXT: [[UV:%[0-9]+]]:gprb(s32), [[UV1:%[0-9]+]]:gprb(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
+...
>From 37ecaa4de066bebb26f435c371e2ca3ed21148aa Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Tue, 21 Nov 2023 17:42:57 -0800
Subject: [PATCH 2/6] clang-format
---
llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index a9de87594d22055..3163b7cd5febdd1 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -81,7 +81,7 @@ class RISCVInstructionSelector : public InstructionSelector {
void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
MachineIRBuilder &MIB) const;
bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
- MachineRegisterInfo &MRI) const;
+ MachineRegisterInfo &MRI) const;
bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) const;
@@ -672,8 +672,7 @@ bool RISCVInstructionSelector::selectUnmergeValues(
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)))
+ if (!isRegInFprb(Src, MRI) || !(isRegInGprb(Lo, MRI) && isRegInGprb(Hi, MRI)))
return false;
MachineInstr *Result = MIB.buildInstr(RISCV::SplitF64Pseudo, {Lo, Hi}, {Src});
@@ -765,12 +764,12 @@ const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
}
bool RISCVInstructionSelector::isRegInGprb(Register Reg,
- MachineRegisterInfo &MRI) const {
+ MachineRegisterInfo &MRI) const {
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::GPRBRegBankID;
}
bool RISCVInstructionSelector::isRegInFprb(Register Reg,
- MachineRegisterInfo &MRI) const {
+ MachineRegisterInfo &MRI) const {
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::FPRBRegBankID;
}
>From c1cc9777440151c9fa343338704a622850370e6a Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Mon, 27 Nov 2023 14:02:03 -0800
Subject: [PATCH 3/6] !fixup simplify regbank checks; use setDesc
---
.../RISCV/GISel/RISCVInstructionSelector.cpp | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 3163b7cd5febdd1..4ed2805edb45b64 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -653,13 +653,10 @@ bool RISCVInstructionSelector::selectMergeValues(
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)))
+ if (!isRegInFprb(Dst, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
return false;
- MachineInstr *Result =
- MIB.buildInstr(RISCV::BuildPairF64Pseudo, {Dst}, {Lo, Hi});
-
- MI.eraseFromParent();
- return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI);
+ MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo));
+ return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
}
bool RISCVInstructionSelector::selectUnmergeValues(
@@ -672,12 +669,10 @@ bool RISCVInstructionSelector::selectUnmergeValues(
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)))
+ if (!isRegInFprb(Src, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
return false;
- MachineInstr *Result = MIB.buildInstr(RISCV::SplitF64Pseudo, {Lo, Hi}, {Src});
-
- MI.eraseFromParent();
- return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI);
+ MI.setDesc(TII.get(RISCV::SplitF64Pseudo));
+ return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
}
bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,
>From ec6e5c05876f742a3550a7c320890122e790ae14 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Mon, 27 Nov 2023 17:38:24 -0800
Subject: [PATCH 4/6] !fixup move tests out of legalizer/rvXX
---
.../legalizer/{rv32/merge-unmerge.mir => merge-unmerge-rv32.mir} | 0
.../legalizer/{rv64/merge-unmerge.mir => merge-unmerge-rv64.mir} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename llvm/test/CodeGen/RISCV/GlobalISel/legalizer/{rv32/merge-unmerge.mir => merge-unmerge-rv32.mir} (100%)
rename llvm/test/CodeGen/RISCV/GlobalISel/legalizer/{rv64/merge-unmerge.mir => merge-unmerge-rv64.mir} (100%)
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.mir
similarity index 100%
rename from llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv32/merge-unmerge.mir
rename to llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.mir
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv64.mir
similarity index 100%
rename from llvm/test/CodeGen/RISCV/GlobalISel/legalizer/rv64/merge-unmerge.mir
rename to llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv64.mir
>From aec060d604923a669cdb1e0b6e0f063eaadaebdf Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Mon, 27 Nov 2023 17:45:05 -0800
Subject: [PATCH 5/6] !fixup specify rv32d in test
---
.../legalizer/{merge-unmerge-d.mir => merge-unmerge-rv32d.mir} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename llvm/test/CodeGen/RISCV/GlobalISel/legalizer/{merge-unmerge-d.mir => merge-unmerge-rv32d.mir} (100%)
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32d.mir
similarity index 100%
rename from llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir
rename to llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32d.mir
>From 75985028729c6115626e0c78c17cc1e082d103a1 Mon Sep 17 00:00:00 2001
From: Michael Maitland <michaeltmaitland at gmail.com>
Date: Mon, 27 Nov 2023 17:56:55 -0800
Subject: [PATCH 6/6] !fixup remove assert; rename test; only legal for rv32;
remove fixme
---
llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 13 +++++++------
.../Target/RISCV/GISel/RISCVRegisterBankInfo.cpp | 6 ------
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 3ea8191d03e144c..b26a2f3b912be9b 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -85,12 +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)
- .legalIf([=, &ST](const LegalityQuery &Query) -> bool {
- return ST.hasStdExtD() && typeIs(LitTyIdx, s32)(Query) &&
- typeIs(BigTyIdx, s64)(Query);
- })
- .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);
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 50cfb3dbd50fa98..cf0ff63a5e51c29 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -425,12 +425,9 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
}
case TargetOpcode::G_MERGE_VALUES: {
// Use FPR64 for s64 merge on rv32.
- assert(MI.getNumOperands() == 3 && "Unsupported G_MERGE_VALUES");
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
- // FIXME: OpdsMapping[0, 1] should probably visit their uses to determine
- // if GPRValueMapping or FPRValueMapping
OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
OpdsMapping[1] = GPRValueMapping;
OpdsMapping[2] = GPRValueMapping;
@@ -439,12 +436,9 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
}
case TargetOpcode::G_UNMERGE_VALUES: {
// Use FPR64 for s64 unmerge on rv32.
- assert(MI.getNumOperands() == 3 && "Unsupported G_UNMERGE_VALUES");
LLT Ty = MRI.getType(MI.getOperand(2).getReg());
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
- // FIXME: OpdsMapping[0, 1] should probably visit their uses to determine
- // if GPRValueMapping or FPRValueMapping
OpdsMapping[0] = GPRValueMapping;
OpdsMapping[1] = GPRValueMapping;
OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
More information about the llvm-commits
mailing list