-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
[RISCV][GISEL] legalize, regbankselect, and instruction-select for G_… #73061
Conversation
@llvm/pr-subscribers-backend-risc-v @llvm/pr-subscribers-llvm-globalisel Author: Michael Maitland (michaelmaitland) Changes…[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. Patch is 21.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/73061.diff 9 Files Affected:
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 3c72269d1e00c2f..1ad26bf05784e83 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;
@@ -72,6 +75,10 @@ class RISCVInstructionSelector : public InstructionSelector {
MachineRegisterInfo &MRI) const;
bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) 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;
@@ -564,11 +571,53 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
return selectSelect(MI, MIB, MRI);
case TargetOpcode::G_FCMP:
return selectFPCompare(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) {
@@ -652,6 +701,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 9eb5812e024b915..6155e94b58e7343 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 6d77e2b7edd9010..cf5f67ec80fd691 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -353,6 +353,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...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-d.mir
Outdated
Show resolved
Hide resolved
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
…[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.
2e8beaf
to
7598502
Compare
…[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.