Skip to content

Commit dbb9043

Browse files
[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.
1 parent 6976dac commit dbb9043

File tree

9 files changed

+485
-2
lines changed

9 files changed

+485
-2
lines changed

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class RISCVInstructionSelector : public InstructionSelector {
4848
const TargetRegisterClass *
4949
getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;
5050

51+
bool isRegInGprb(Register Reg, MachineRegisterInfo &MRI) const;
52+
bool isRegInFprb(Register Reg, MachineRegisterInfo &MRI) const;
53+
5154
// tblgen-erated 'select' implementation, used as the initial selector for
5255
// the patterns that don't require complex C++.
5356
bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
@@ -77,6 +80,10 @@ class RISCVInstructionSelector : public InstructionSelector {
7780
MachineRegisterInfo &MRI) const;
7881
void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
7982
MachineIRBuilder &MIB) const;
83+
bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
84+
MachineRegisterInfo &MRI) const;
85+
bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB,
86+
MachineRegisterInfo &MRI) const;
8087

8188
ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
8289
ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
@@ -627,11 +634,47 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
627634
}
628635
case TargetOpcode::G_IMPLICIT_DEF:
629636
return selectImplicitDef(MI, MIB, MRI);
637+
case TargetOpcode::G_MERGE_VALUES:
638+
return selectMergeValues(MI, MIB, MRI);
639+
case TargetOpcode::G_UNMERGE_VALUES:
640+
return selectUnmergeValues(MI, MIB, MRI);
630641
default:
631642
return false;
632643
}
633644
}
634645

646+
bool RISCVInstructionSelector::selectMergeValues(
647+
MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
648+
assert(MI.getOpcode() == TargetOpcode::G_MERGE_VALUES);
649+
650+
// Build a F64 Pair from operands
651+
if (MI.getNumOperands() != 3)
652+
return false;
653+
Register Dst = MI.getOperand(0).getReg();
654+
Register Lo = MI.getOperand(1).getReg();
655+
Register Hi = MI.getOperand(2).getReg();
656+
if (!isRegInFprb(Dst, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
657+
return false;
658+
MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo));
659+
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
660+
}
661+
662+
bool RISCVInstructionSelector::selectUnmergeValues(
663+
MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
664+
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
665+
666+
// Split F64 Src into two s32 parts
667+
if (MI.getNumOperands() != 3)
668+
return false;
669+
Register Src = MI.getOperand(2).getReg();
670+
Register Lo = MI.getOperand(0).getReg();
671+
Register Hi = MI.getOperand(1).getReg();
672+
if (!isRegInFprb(Src, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))
673+
return false;
674+
MI.setDesc(TII.get(RISCV::SplitF64Pseudo));
675+
return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);
676+
}
677+
635678
bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,
636679
MachineIRBuilder &MIB,
637680
MachineRegisterInfo &MRI) {
@@ -715,6 +758,16 @@ const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
715758
return nullptr;
716759
}
717760

761+
bool RISCVInstructionSelector::isRegInGprb(Register Reg,
762+
MachineRegisterInfo &MRI) const {
763+
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::GPRBRegBankID;
764+
}
765+
766+
bool RISCVInstructionSelector::isRegInFprb(Register Reg,
767+
MachineRegisterInfo &MRI) const {
768+
return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::FPRBRegBankID;
769+
}
770+
718771
bool RISCVInstructionSelector::selectCopy(MachineInstr &MI,
719772
MachineRegisterInfo &MRI) const {
720773
Register DstReg = MI.getOperand(0).getReg();

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,13 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
8585
for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
8686
unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
8787
unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
88-
getActionDefinitionsBuilder(Op)
89-
.widenScalarToNextPow2(LitTyIdx, XLen)
88+
auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
89+
if (XLen == 32 && ST.hasStdExtD()) {
90+
LLT IdxZeroTy = G_MERGE_VALUES ? s64 : s32;
91+
LLT IdxOneTy = G_MERGE_VALUES ? s32 : s64;
92+
MergeUnmergeActions.legalFor({IdxZeroTy, IdxOneTy});
93+
}
94+
MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
9095
.widenScalarToNextPow2(BigTyIdx, XLen)
9196
.clampScalar(LitTyIdx, sXLen, sXLen)
9297
.clampScalar(BigTyIdx, sXLen, sXLen);

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,28 @@ RISCVRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
423423
OpdsMapping[2] = OpdsMapping[3] = getFPValueMapping(Size);
424424
break;
425425
}
426+
case TargetOpcode::G_MERGE_VALUES: {
427+
// Use FPR64 for s64 merge on rv32.
428+
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
429+
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
430+
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
431+
OpdsMapping[0] = getFPValueMapping(Ty.getSizeInBits());
432+
OpdsMapping[1] = GPRValueMapping;
433+
OpdsMapping[2] = GPRValueMapping;
434+
}
435+
break;
436+
}
437+
case TargetOpcode::G_UNMERGE_VALUES: {
438+
// Use FPR64 for s64 unmerge on rv32.
439+
LLT Ty = MRI.getType(MI.getOperand(2).getReg());
440+
if (GPRSize == 32 && Ty.getSizeInBits() == 64) {
441+
assert(MF.getSubtarget<RISCVSubtarget>().hasStdExtD());
442+
OpdsMapping[0] = GPRValueMapping;
443+
OpdsMapping[1] = GPRValueMapping;
444+
OpdsMapping[2] = getFPValueMapping(Ty.getSizeInBits());
445+
}
446+
break;
447+
}
426448
default:
427449
// By default map all scalars to GPR.
428450
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=instruction-select \
3+
# RUN: -simplify-mir -verify-machineinstrs %s -o - | FileCheck %s
4+
5+
---
6+
name: merge_i64
7+
legalized: true
8+
regBankSelected: true
9+
tracksRegLiveness: true
10+
body: |
11+
bb.0.entry:
12+
liveins: $x10
13+
; CHECK-LABEL: name: merge_i64
14+
; CHECK: liveins: $x10
15+
; CHECK-NEXT: {{ $}}
16+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
17+
; CHECK-NEXT: [[BuildPairF64Pseudo:%[0-9]+]]:fpr64 = BuildPairF64Pseudo [[COPY]], [[COPY]]
18+
; CHECK-NEXT: $f10_d = COPY [[BuildPairF64Pseudo]]
19+
; CHECK-NEXT: PseudoRET implicit $f10_d
20+
%0:gprb(s32) = COPY $x10
21+
%1:fprb(s64) = G_MERGE_VALUES %0(s32), %0(s32)
22+
$f10_d = COPY %1(s64)
23+
PseudoRET implicit $f10_d
24+
...
25+
---
26+
name: unmerge_i32
27+
legalized: true
28+
regBankSelected: true
29+
tracksRegLiveness: true
30+
body: |
31+
bb.0.entry:
32+
liveins: $f10_d
33+
; CHECK-LABEL: name: unmerge_i32
34+
; CHECK: liveins: $f10_d
35+
; CHECK-NEXT: {{ $}}
36+
; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $f10_d
37+
; CHECK-NEXT: [[SplitF64Pseudo:%[0-9]+]]:gpr, [[SplitF64Pseudo1:%[0-9]+]]:gpr = SplitF64Pseudo [[COPY]]
38+
; CHECK-NEXT: $x10 = COPY [[SplitF64Pseudo]]
39+
; CHECK-NEXT: PseudoRET implicit $x10
40+
%0:fprb(s64) = COPY $f10_d
41+
%1:gprb(s32), %2:gprb(s32) = G_UNMERGE_VALUES %0(s64)
42+
$x10 = COPY %1(s32)
43+
PseudoRET implicit $x10
44+
...
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 4
2+
; RUN: llc -mtriple=riscv32 -global-isel -mattr=+d -stop-after=legalizer -verify-machineinstrs < %s \
3+
; RUN: | FileCheck -check-prefixes=CHECK %s
4+
5+
define i64 @double_to_i64(double %a) {
6+
; CHECK-LABEL: name: double_to_i64
7+
; CHECK: bb.1 (%ir-block.0):
8+
; CHECK-NEXT: liveins: $f10_d
9+
; CHECK-NEXT: {{ $}}
10+
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
11+
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
12+
; CHECK-NEXT: $x10 = COPY [[UV]](s32)
13+
; CHECK-NEXT: $x11 = COPY [[UV1]](s32)
14+
; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
15+
%1 = bitcast double %a to i64
16+
ret i64 %1
17+
}
18+
19+
define double @i64_to_double(i64 %a) {
20+
; CHECK-LABEL: name: i64_to_double
21+
; CHECK: bb.1 (%ir-block.0):
22+
; CHECK-NEXT: liveins: $x10, $x11
23+
; CHECK-NEXT: {{ $}}
24+
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
25+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
26+
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
27+
; CHECK-NEXT: $f10_d = COPY [[MV]](s64)
28+
; CHECK-NEXT: PseudoRET implicit $f10_d
29+
%1 = bitcast i64 %a to double
30+
ret double %1
31+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - \
3+
# RUN: | FileCheck --check-prefix=RV32 %s
4+
5+
---
6+
name: merge_i32
7+
body: |
8+
bb.0.entry:
9+
liveins: $x10
10+
; RV32-LABEL: name: merge_i32
11+
; RV32: liveins: $x10
12+
; RV32-NEXT: {{ $}}
13+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
14+
; RV32-NEXT: [[ASSERT_ZEXT:%[0-9]+]]:_(s32) = G_ASSERT_ZEXT [[COPY]], 16
15+
; RV32-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
16+
; RV32-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[ASSERT_ZEXT]], [[C]](s32)
17+
; RV32-NEXT: [[OR:%[0-9]+]]:_(s32) = G_OR [[ASSERT_ZEXT]], [[SHL]]
18+
; RV32-NEXT: $x10 = COPY [[OR]](s32)
19+
; RV32-NEXT: PseudoRET implicit $x10
20+
%0:_(s32) = COPY $x10
21+
%1:_(s32) = G_ASSERT_ZEXT %0, 16
22+
%2:_(s16) = G_TRUNC %1(s32)
23+
%3:_(s32) = G_MERGE_VALUES %2(s16), %2(s16)
24+
$x10 = COPY %3(s32)
25+
PseudoRET implicit $x10
26+
...
27+
---
28+
name: merge_i64
29+
body: |
30+
bb.0.entry:
31+
liveins: $x10
32+
; RV32-LABEL: name: merge_i64
33+
; RV32: liveins: $x10
34+
; RV32-NEXT: {{ $}}
35+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
36+
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
37+
; RV32-NEXT: PseudoRET implicit $x10
38+
%0:_(s32) = COPY $x10
39+
%1:_(s64) = G_MERGE_VALUES %0(s32), %0(s32)
40+
%2:_(s32) = G_TRUNC %1(s64)
41+
$x10 = COPY %2(s32)
42+
PseudoRET implicit $x10
43+
...
44+
---
45+
name: merge_i128
46+
body: |
47+
bb.0.entry:
48+
liveins: $x10
49+
; RV32-LABEL: name: merge_i128
50+
; RV32: liveins: $x10
51+
; RV32-NEXT: {{ $}}
52+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
53+
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
54+
; RV32-NEXT: PseudoRET implicit $x10
55+
%1:_(s32) = COPY $x10
56+
%2:_(s64) = G_ZEXT %1(s32)
57+
%0:_(s128) = G_MERGE_VALUES %2(s64), %2(s64)
58+
%3:_(s32) = G_TRUNC %0(s128)
59+
$x10 = COPY %3(s32)
60+
PseudoRET implicit $x10
61+
...
62+
---
63+
name: unmerge_i32
64+
body: |
65+
bb.0.entry:
66+
liveins: $x10
67+
; RV32-LABEL: name: unmerge_i32
68+
; RV32: liveins: $x10
69+
; RV32-NEXT: {{ $}}
70+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
71+
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
72+
; RV32-NEXT: PseudoRET implicit $x10
73+
%0:_(s32) = COPY $x10
74+
%1:_(s64) = G_ZEXT %0(s32)
75+
%2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64)
76+
$x10 = COPY %2(s32)
77+
PseudoRET implicit $x10
78+
...
79+
---
80+
name: unmerge_i64
81+
body: |
82+
bb.0.entry:
83+
liveins: $x10
84+
; RV32-LABEL: name: unmerge_i64
85+
; RV32: liveins: $x10
86+
; RV32-NEXT: {{ $}}
87+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
88+
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
89+
; RV32-NEXT: PseudoRET implicit $x10
90+
%0:_(s32) = COPY $x10
91+
%1:_(s64) = G_ZEXT %0(s32)
92+
%2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %1(s64)
93+
$x10 = COPY %2(s32)
94+
PseudoRET implicit $x10
95+
...
96+
---
97+
name: unmerge_i128
98+
body: |
99+
bb.0.entry:
100+
liveins: $x10
101+
; RV32-LABEL: name: unmerge_i128
102+
; RV32: liveins: $x10
103+
; RV32-NEXT: {{ $}}
104+
; RV32-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
105+
; RV32-NEXT: $x10 = COPY [[C]](s32)
106+
; RV32-NEXT: PseudoRET implicit $x10
107+
%0:_(s32) = COPY $x10
108+
%1:_(s128) = G_ZEXT %0(s32)
109+
%2:_(s64), %3:_(s64) = G_UNMERGE_VALUES %1(s128)
110+
%4:_(s32) = G_TRUNC %3(s64)
111+
$x10 = COPY %4(s32)
112+
PseudoRET implicit $x10
113+
...
114+
---
115+
name: unmerge_i256
116+
body: |
117+
bb.0.entry:
118+
liveins: $x10
119+
; RV32-LABEL: name: unmerge_i256
120+
; RV32: liveins: $x10
121+
; RV32-NEXT: {{ $}}
122+
; RV32-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
123+
; RV32-NEXT: $x10 = COPY [[COPY]](s32)
124+
; RV32-NEXT: PseudoRET implicit $x10
125+
%0:_(s32) = COPY $x10
126+
%1:_(s256) = G_ZEXT %0(s32)
127+
%2:_(s128), %3:_(s128) = G_UNMERGE_VALUES %1(s256)
128+
%4:_(s32) = G_TRUNC %2(s128)
129+
$x10 = COPY %4(s32)
130+
PseudoRET implicit $x10
131+
...
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=riscv32 -mattr=+d -run-pass=legalizer %s -o - \
3+
# RUN: | FileCheck %s
4+
5+
---
6+
name: merge_i64
7+
body: |
8+
bb.0.entry:
9+
liveins: $x10
10+
; CHECK-LABEL: name: merge_i64
11+
; CHECK: liveins: $x10
12+
; CHECK-NEXT: {{ $}}
13+
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
14+
; CHECK-NEXT: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY]](s32)
15+
; CHECK-NEXT: $f10_d = COPY [[MV]](s64)
16+
; CHECK-NEXT: PseudoRET implicit $f10_d
17+
%0:_(s32) = COPY $x10
18+
%1:_(s64) = G_MERGE_VALUES %0(s32), %0(s32)
19+
$f10_d = COPY %1(s64)
20+
PseudoRET implicit $f10_d
21+
...
22+
---
23+
name: unmerge_i32
24+
body: |
25+
bb.0.entry:
26+
liveins: $f10_d
27+
; CHECK-LABEL: name: unmerge_i32
28+
; CHECK: liveins: $f10_d
29+
; CHECK-NEXT: {{ $}}
30+
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $f10_d
31+
; CHECK-NEXT: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]](s64)
32+
; CHECK-NEXT: $x10 = COPY [[UV]](s32)
33+
; CHECK-NEXT: PseudoRET implicit $x10
34+
%0:_(s64) = COPY $f10_d
35+
%1:_(s32), %2:_(s32) = G_UNMERGE_VALUES %0(s64)
36+
$x10 = COPY %1(s32)
37+
PseudoRET implicit $x10
38+
...

0 commit comments

Comments
 (0)