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

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 30 08:53:32 PST 2023


Author: Michael Maitland
Date: 2023-11-30T11:53:25-05:00
New Revision: dbb9043dea238fa4e5b6a9a7fef99623b543493e

URL: https://github.com/llvm/llvm-project/commit/dbb9043dea238fa4e5b6a9a7fef99623b543493e
DIFF: https://github.com/llvm/llvm-project/commit/dbb9043dea238fa4e5b6a9a7fef99623b543493e.diff

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

…[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.

Added: 
    llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/merge-unmerge-rv32.mir
    llvm/test/CodeGen/RISCV/GlobalISel/irtranslator/bitcast-between-f64-and-i64.ll
    llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.mir
    llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32d.mir
    llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv64.mir
    llvm/test/CodeGen/RISCV/GlobalISel/regbankselect/merge-unmerge-rv32.mir

Modified: 
    llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
    llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
    llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 6e5829ba93a7128..4ed2805edb45b64 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,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) {
@@ -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();

diff  --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index d745e0957168ce7..b26a2f3b912be9b 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -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);

diff  --git a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
index 8f274f0417cac62..cf0ff63a5e51c29 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp
@@ -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) {

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-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.mir
new file mode 100644
index 000000000000000..2e4a39c468111f2
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32.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/merge-unmerge-rv32d.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32d.mir
new file mode 100644
index 000000000000000..10c775cd9ecfe1a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv32d.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/merge-unmerge-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv64.mir
new file mode 100644
index 000000000000000..3cf3a7c24863936
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer/merge-unmerge-rv64.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
+...


        


More information about the llvm-commits mailing list