Skip to content

Commit 785b16a

Browse files
authored
[RISCV][GISel] Support G_MERGE_VALUES/G_UNMERGE_VALUES with Zfa. (#120379)
Without Zfa we use pseudos that are lowered to a stack load/store. With Zfa we have instructions that can move a pair of registers to an FPR. Or move the high or low half of an FPR to a GPR. I've used a GINodeEquiv to make use of 3 of the 4 tablegen patterns. The split case with Zfa requires 2 instructions which I'm doing through custom isel like we do in SelectionDAG.
1 parent 4e36d5b commit 785b16a

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ class RISCVInstructionSelector : public InstructionSelector {
8080
bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB) const;
8181
void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
8282
MachineIRBuilder &MIB) const;
83-
bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB) const;
8483
bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB) const;
8584

8685
ComplexRendererFns selectShiftMask(MachineOperand &Root,
@@ -732,35 +731,20 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
732731
}
733732
case TargetOpcode::G_IMPLICIT_DEF:
734733
return selectImplicitDef(MI, MIB);
735-
case TargetOpcode::G_MERGE_VALUES:
736-
return selectMergeValues(MI, MIB);
737734
case TargetOpcode::G_UNMERGE_VALUES:
738735
return selectUnmergeValues(MI, MIB);
739736
default:
740737
return false;
741738
}
742739
}
743740

744-
bool RISCVInstructionSelector::selectMergeValues(MachineInstr &MI,
745-
MachineIRBuilder &MIB) const {
746-
assert(MI.getOpcode() == TargetOpcode::G_MERGE_VALUES);
747-
748-
// Build a F64 Pair from operands
749-
if (MI.getNumOperands() != 3)
750-
return false;
751-
Register Dst = MI.getOperand(0).getReg();
752-
Register Lo = MI.getOperand(1).getReg();
753-
Register Hi = MI.getOperand(2).getReg();
754-
if (!isRegInFprb(Dst) || !isRegInGprb(Lo) || !isRegInGprb(Hi))
755-
return false;
756-
MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo));
757-
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
758-
}
759-
760741
bool RISCVInstructionSelector::selectUnmergeValues(
761742
MachineInstr &MI, MachineIRBuilder &MIB) const {
762743
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
763744

745+
if (!Subtarget->hasStdExtZfa())
746+
return false;
747+
764748
// Split F64 Src into two s32 parts
765749
if (MI.getNumOperands() != 3)
766750
return false;
@@ -769,8 +753,17 @@ bool RISCVInstructionSelector::selectUnmergeValues(
769753
Register Hi = MI.getOperand(1).getReg();
770754
if (!isRegInFprb(Src) || !isRegInGprb(Lo) || !isRegInGprb(Hi))
771755
return false;
772-
MI.setDesc(TII.get(RISCV::SplitF64Pseudo));
773-
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
756+
757+
MachineInstr *ExtractLo = MIB.buildInstr(RISCV::FMV_X_W_FPR64, {Lo}, {Src});
758+
if (!constrainSelectedInstRegOperands(*ExtractLo, TII, TRI, RBI))
759+
return false;
760+
761+
MachineInstr *ExtractHi = MIB.buildInstr(RISCV::FMVH_X_D, {Hi}, {Src});
762+
if (!constrainSelectedInstRegOperands(*ExtractHi, TII, TRI, RBI))
763+
return false;
764+
765+
MI.eraseFromParent();
766+
return true;
774767
}
775768

776769
bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,

llvm/lib/Target/RISCV/RISCVInstrInfoD.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ def SDT_RISCVSplitF64 : SDTypeProfile<2, 1, [SDTCisVT<0, i32>,
2323
SDTCisVT<2, f64>]>;
2424

2525
def RISCVBuildPairF64 : SDNode<"RISCVISD::BuildPairF64", SDT_RISCVBuildPairF64>;
26+
def : GINodeEquiv<G_MERGE_VALUES, RISCVBuildPairF64>;
2627
def RISCVSplitF64 : SDNode<"RISCVISD::SplitF64", SDT_RISCVSplitF64>;
28+
def : GINodeEquiv<G_UNMERGE_VALUES, RISCVSplitF64>;
2729

2830
def AddrRegImmINX : ComplexPattern<iPTR, 2, "SelectAddrRegImmRV32Zdinx">;
2931

llvm/test/CodeGen/RISCV/GlobalISel/double-zfa.ll

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2-
32
; RUN: llc -mtriple=riscv32 -mattr=+zfa,d -global-isel < %s \
4-
; RUN: | FileCheck %s
3+
; RUN: | FileCheck %s --check-prefixes=CHECK,RV32IDZFA
54
; RUN: llc -mtriple=riscv64 -mattr=+zfa,d -global-isel < %s \
6-
; RUN: | FileCheck %s
5+
; RUN: | FileCheck %s --check-prefixes=CHECK,RV64DZFA
76

87

98
define double @fceil(double %a) {
@@ -86,3 +85,32 @@ define double @fminimum(double %a, double %b) {
8685
%c = call double @llvm.minimum.f64(double %a, double %b)
8786
ret double %c
8887
}
88+
89+
define i64 @fmvh_x_d(double %fa) {
90+
; RV32IDZFA-LABEL: fmvh_x_d:
91+
; RV32IDZFA: # %bb.0:
92+
; RV32IDZFA-NEXT: fmv.x.w a0, fa0
93+
; RV32IDZFA-NEXT: fmvh.x.d a1, fa0
94+
; RV32IDZFA-NEXT: ret
95+
;
96+
; RV64DZFA-LABEL: fmvh_x_d:
97+
; RV64DZFA: # %bb.0:
98+
; RV64DZFA-NEXT: fmv.x.d a0, fa0
99+
; RV64DZFA-NEXT: ret
100+
%i = bitcast double %fa to i64
101+
ret i64 %i
102+
}
103+
104+
define double @fmvp_d_x(i64 %a) {
105+
; RV32IDZFA-LABEL: fmvp_d_x:
106+
; RV32IDZFA: # %bb.0:
107+
; RV32IDZFA-NEXT: fmvp.d.x fa0, a0, a1
108+
; RV32IDZFA-NEXT: ret
109+
;
110+
; RV64DZFA-LABEL: fmvp_d_x:
111+
; RV64DZFA: # %bb.0:
112+
; RV64DZFA-NEXT: fmv.d.x fa0, a0
113+
; RV64DZFA-NEXT: ret
114+
%or = bitcast i64 %a to double
115+
ret double %or
116+
}

0 commit comments

Comments
 (0)