Skip to content

Commit b3afad0

Browse files
author
Quentin Colombet
committed
[GlobalISel] Add a X, Y = G_UNMERGE(G_ZEXT Z) -> X = G_ZEXT Z; Y = 0 combine
Add a combiner helper to transform unmerge of zext into one zext and a constant 0 Differential Revision: https://reviews.llvm.org/D87427
1 parent d232112 commit b3afad0

File tree

9 files changed

+424
-391
lines changed

9 files changed

+424
-391
lines changed

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ class CombinerHelper {
262262
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI);
263263
bool applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI);
264264

265+
/// Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0
266+
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI);
267+
bool applyCombineUnmergeZExtToZExt(MachineInstr &MI);
268+
265269
/// Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
266270
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg);
267271
bool applyCombineI2PToP2I(MachineInstr &MI, Register &Reg);

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@ def unmerge_dead_to_trunc : GICombineRule<
429429
(apply [{ return Helper.applyCombineUnmergeWithDeadLanesToTrunc(*${d}); }])
430430
>;
431431

432+
// Transform x,y = unmerge(zext(z)) -> x = zext z; y = 0.
433+
def unmerge_zext_to_zext : GICombineRule<
434+
(defs root:$d),
435+
(match (wip_match_opcode G_UNMERGE_VALUES): $d,
436+
[{ return Helper.matchCombineUnmergeZExtToZExt(*${d}); }]),
437+
(apply [{ return Helper.applyCombineUnmergeZExtToZExt(*${d}); }])
438+
>;
439+
432440
// FIXME: These should use the custom predicate feature once it lands.
433441
def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
434442
undef_to_negative_one,
@@ -460,4 +468,5 @@ def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain,
460468
width_reduction_combines, select_combines,
461469
known_bits_simplifications, ext_ext_fold,
462470
not_cmp_fold, opt_brcond_by_inverting_cond,
463-
unmerge_merge, fabs_fabs_fold, unmerge_cst, unmerge_dead_to_trunc]>;
471+
unmerge_merge, fabs_fabs_fold, unmerge_cst, unmerge_dead_to_trunc,
472+
unmerge_zext_to_zext]>;

llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,67 @@ bool CombinerHelper::applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI) {
16871687
return true;
16881688
}
16891689

1690+
bool CombinerHelper::matchCombineUnmergeZExtToZExt(MachineInstr &MI) {
1691+
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
1692+
"Expected an unmerge");
1693+
Register Dst0Reg = MI.getOperand(0).getReg();
1694+
LLT Dst0Ty = MRI.getType(Dst0Reg);
1695+
// G_ZEXT on vector applies to each lane, so it will
1696+
// affect all destinations. Therefore we won't be able
1697+
// to simplify the unmerge to just the first definition.
1698+
if (Dst0Ty.isVector())
1699+
return false;
1700+
Register SrcReg = MI.getOperand(MI.getNumDefs()).getReg();
1701+
LLT SrcTy = MRI.getType(SrcReg);
1702+
if (SrcTy.isVector())
1703+
return false;
1704+
1705+
Register ZExtSrcReg;
1706+
if (!mi_match(SrcReg, MRI, m_GZExt(m_Reg(ZExtSrcReg))))
1707+
return false;
1708+
1709+
// Finally we can replace the first definition with
1710+
// a zext of the source if the definition is big enough to hold
1711+
// all of ZExtSrc bits.
1712+
LLT ZExtSrcTy = MRI.getType(ZExtSrcReg);
1713+
return ZExtSrcTy.getSizeInBits() <= Dst0Ty.getSizeInBits();
1714+
}
1715+
1716+
bool CombinerHelper::applyCombineUnmergeZExtToZExt(MachineInstr &MI) {
1717+
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
1718+
"Expected an unmerge");
1719+
1720+
Register Dst0Reg = MI.getOperand(0).getReg();
1721+
1722+
MachineInstr *ZExtInstr =
1723+
MRI.getVRegDef(MI.getOperand(MI.getNumDefs()).getReg());
1724+
assert(ZExtInstr && ZExtInstr->getOpcode() == TargetOpcode::G_ZEXT &&
1725+
"Expecting a G_ZEXT");
1726+
1727+
Register ZExtSrcReg = ZExtInstr->getOperand(1).getReg();
1728+
LLT Dst0Ty = MRI.getType(Dst0Reg);
1729+
LLT ZExtSrcTy = MRI.getType(ZExtSrcReg);
1730+
1731+
Builder.setInstrAndDebugLoc(MI);
1732+
1733+
if (Dst0Ty.getSizeInBits() > ZExtSrcTy.getSizeInBits()) {
1734+
Builder.buildZExt(Dst0Reg, ZExtSrcReg);
1735+
} else {
1736+
assert(Dst0Ty.getSizeInBits() == ZExtSrcTy.getSizeInBits() &&
1737+
"ZExt src doesn't fit in destination");
1738+
replaceRegWith(MRI, Dst0Reg, ZExtSrcReg);
1739+
}
1740+
1741+
Register ZeroReg;
1742+
for (unsigned Idx = 1, EndIdx = MI.getNumDefs(); Idx != EndIdx; ++Idx) {
1743+
if (!ZeroReg)
1744+
ZeroReg = Builder.buildConstant(Dst0Ty, 0).getReg(0);
1745+
replaceRegWith(MRI, MI.getOperand(Idx).getReg(), ZeroReg);
1746+
}
1747+
MI.eraseFromParent();
1748+
return true;
1749+
}
1750+
16901751
bool CombinerHelper::matchCombineShiftToUnmerge(MachineInstr &MI,
16911752
unsigned TargetShiftSize,
16921753
unsigned &ShiftVal) {

llvm/test/CodeGen/AArch64/GlobalISel/combine-unmerge.mir

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,110 @@ body: |
369369
%1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %0(s64)
370370
$w0 = COPY %1(<2 x s16>)
371371
...
372+
373+
# Transform unmerge(zext) into zext.
374+
# In that test, the source of the zext is same size as the first definition
375+
# of the unmerge. Therefore a we can just reuse the input of the zext for
376+
# this definition.
377+
---
378+
name: test_combine_unmerge_zext_to_zext_same_size
379+
body: |
380+
bb.1:
381+
; CHECK-LABEL: name: test_combine_unmerge_zext_to_zext_same_size
382+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
383+
; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
384+
; CHECK: $w0 = COPY [[COPY]](s32)
385+
; CHECK: $w1 = COPY [[C]](s32)
386+
%0:_(s32) = COPY $w0
387+
%3:_(s64) = G_ZEXT %0(s32)
388+
%1:_(s32),%2:_(s32) = G_UNMERGE_VALUES %3(s64)
389+
$w0 = COPY %1(s32)
390+
$w1 = COPY %2(s32)
391+
...
392+
393+
# Transform unmerge(zext) into zext.
394+
# In that test, the source of the zext is smaller than the first definition
395+
# of the unmerge. Therefore a G_ZEXT is required.
396+
---
397+
name: test_combine_unmerge_zext_to_zext
398+
body: |
399+
bb.1:
400+
; CHECK-LABEL: name: test_combine_unmerge_zext_to_zext
401+
; CHECK: [[COPY:%[0-9]+]]:_(s8) = COPY $b0
402+
; CHECK: [[ZEXT:%[0-9]+]]:_(s16) = G_ZEXT [[COPY]](s8)
403+
; CHECK: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
404+
; CHECK: $h0 = COPY [[ZEXT]](s16)
405+
; CHECK: $h1 = COPY [[C]](s16)
406+
; CHECK: $h2 = COPY [[C]](s16)
407+
; CHECK: $h3 = COPY [[C]](s16)
408+
%0:_(s8) = COPY $b0
409+
%3:_(s64) = G_ZEXT %0(s8)
410+
%1:_(s16),%2:_(s16),%4:_(s16),%5:_(s16) = G_UNMERGE_VALUES %3(s64)
411+
$h0 = COPY %1(s16)
412+
$h1 = COPY %2(s16)
413+
$h2 = COPY %4(s16)
414+
$h3 = COPY %5(s16)
415+
...
416+
417+
# Check that we don't apply the unmerge(zext) to zext transformation
418+
# when the first destination of the unmerge is smaller than the source
419+
# of the zext.
420+
---
421+
name: test_dont_combine_unmerge_zext_to_zext_src_bigger
422+
body: |
423+
bb.1:
424+
; CHECK-LABEL: name: test_dont_combine_unmerge_zext_to_zext_src_bigger
425+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
426+
; CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[COPY]](s32)
427+
; CHECK: [[UV:%[0-9]+]]:_(s16), [[UV1:%[0-9]+]]:_(s16), [[UV2:%[0-9]+]]:_(s16), [[UV3:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[ZEXT]](s64)
428+
; CHECK: $h0 = COPY [[UV]](s16)
429+
; CHECK: $h1 = COPY [[UV1]](s16)
430+
; CHECK: $h2 = COPY [[UV2]](s16)
431+
; CHECK: $h3 = COPY [[UV3]](s16)
432+
%0:_(s32) = COPY $w0
433+
%3:_(s64) = G_ZEXT %0(s32)
434+
%1:_(s16),%2:_(s16),%4:_(s16),%5:_(s16) = G_UNMERGE_VALUES %3(s64)
435+
$h0 = COPY %1(s16)
436+
$h1 = COPY %2(s16)
437+
$h2 = COPY %4(s16)
438+
$h3 = COPY %5(s16)
439+
...
440+
441+
# Check that we don't apply the unmerge(zext) to zext transformation
442+
# when the input zext deals with a vector type.
443+
---
444+
name: test_dont_combine_unmerge_zext_to_zext_src_vector
445+
body: |
446+
bb.1:
447+
; CHECK-LABEL: name: test_dont_combine_unmerge_zext_to_zext_src_vector
448+
; CHECK: [[COPY:%[0-9]+]]:_(<2 x s16>) = COPY $w0
449+
; CHECK: [[ZEXT:%[0-9]+]]:_(<2 x s32>) = G_ZEXT [[COPY]](<2 x s16>)
450+
; CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ZEXT]](<2 x s32>)
451+
; CHECK: $w0 = COPY [[UV]](s32)
452+
; CHECK: $w1 = COPY [[UV1]](s32)
453+
%0:_(<2 x s16>) = COPY $w0
454+
%3:_(<2 x s32>) = G_ZEXT %0(<2 x s16>)
455+
%1:_(s32),%2:_(s32) = G_UNMERGE_VALUES %3(<2 x s32>)
456+
$w0 = COPY %1(s32)
457+
$w1 = COPY %2(s32)
458+
...
459+
460+
# Check that we don't apply the unmerge(zext) to zext transformation
461+
# when the destination type is a vector type.
462+
# We could actually handle this case but we would need to insert a cast.
463+
---
464+
name: test_dont_combine_unmerge_zext_to_zext_dst_vector
465+
body: |
466+
bb.1:
467+
; CHECK-LABEL: name: test_dont_combine_unmerge_zext_to_zext_dst_vector
468+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
469+
; CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[COPY]](s32)
470+
; CHECK: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[ZEXT]](s64)
471+
; CHECK: $w0 = COPY [[UV]](<2 x s16>)
472+
; CHECK: $w1 = COPY [[UV1]](<2 x s16>)
473+
%0:_(s32) = COPY $w0
474+
%3:_(s64) = G_ZEXT %0(s32)
475+
%1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %3(s64)
476+
$w0 = COPY %1(<2 x s16>)
477+
$w1 = COPY %2(<2 x s16>)
478+
...

0 commit comments

Comments
 (0)