diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 6e5829ba93a71..4ed2805edb45b 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 d745e0957168c..b26a2f3b912be 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 8f274f0417cac..cf0ff63a5e51c 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().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().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 0000000000000..11d3bf6a4cd0e --- /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 0000000000000..5461f7366c523 --- /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 0000000000000..2e4a39c468111 --- /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 0000000000000..10c775cd9ecfe --- /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 0000000000000..3cf3a7c248639 --- /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 0000000000000..4785b86a8a786 --- /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 +...