Skip to content

Commit 6d90ac1

Browse files
author
Thorsten Schütt
authored
[GlobalIsel] Combine freeze (#93239)
1 parent 1de6011 commit 6d90ac1

File tree

11 files changed

+1971
-475
lines changed

11 files changed

+1971
-475
lines changed

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -840,10 +840,6 @@ class CombinerHelper {
840840
/// Combine extract vector element.
841841
bool matchExtractVectorElement(MachineInstr &MI, BuildFnTy &MatchInfo);
842842

843-
/// Combine extract vector element with freeze on the vector register.
844-
bool matchExtractVectorElementWithFreeze(const MachineOperand &MO,
845-
BuildFnTy &MatchInfo);
846-
847843
/// Combine extract vector element with a build vector on the vector register.
848844
bool matchExtractVectorElementWithBuildVector(const MachineOperand &MO,
849845
BuildFnTy &MatchInfo);

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,13 +1532,6 @@ def extract_vector_element_build_vector_trunc8 : GICombineRule<
15321532
[{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]),
15331533
(apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
15341534

1535-
def extract_vector_element_freeze : GICombineRule<
1536-
(defs root:$root, build_fn_matchinfo:$matchinfo),
1537-
(match (G_FREEZE $src, $input),
1538-
(G_EXTRACT_VECTOR_ELT $root, $src, $idx),
1539-
[{ return Helper.matchExtractVectorElementWithFreeze(${root}, ${matchinfo}); }]),
1540-
(apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
1541-
15421535
def sext_trunc : GICombineRule<
15431536
(defs root:$root, build_fn_matchinfo:$matchinfo),
15441537
(match (G_TRUNC $src, $x, (MIFlags NoSWrap)),
@@ -1636,7 +1629,6 @@ extract_vector_element_build_vector_trunc5,
16361629
extract_vector_element_build_vector_trunc6,
16371630
extract_vector_element_build_vector_trunc7,
16381631
extract_vector_element_build_vector_trunc8,
1639-
extract_vector_element_freeze,
16401632
extract_vector_element_shuffle_vector,
16411633
insert_vector_element_extract_vector_element
16421634
]>;
@@ -1713,6 +1705,17 @@ def integer_reassoc_combines: GICombineGroup<[
17131705
APlusBMinusCPlusA
17141706
]>;
17151707

1708+
def freeze_of_non_undef_non_poison : GICombineRule<
1709+
(defs root:$root),
1710+
(match (G_FREEZE $root, $src),
1711+
[{ return isGuaranteedNotToBeUndefOrPoison(${src}.getReg(), MRI); }]),
1712+
(apply (GIReplaceReg $root, $src))>;
1713+
1714+
def freeze_combines: GICombineGroup<[
1715+
freeze_of_non_undef_non_poison,
1716+
push_freeze_to_prevent_poison_from_propagating
1717+
]>;
1718+
17161719
// FIXME: These should use the custom predicate feature once it lands.
17171720
def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
17181721
undef_to_negative_one,
@@ -1771,7 +1774,7 @@ def constant_fold_binops : GICombineGroup<[constant_fold_binop,
17711774
constant_fold_fp_binop]>;
17721775

17731776
def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
1774-
vector_ops_combines,
1777+
vector_ops_combines, freeze_combines,
17751778
insert_vec_elt_combines, extract_vec_elt_combines, combines_for_extload,
17761779
combine_extracted_vector_load,
17771780
undef_combines, identity_combines, phi_combines,
@@ -1793,8 +1796,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
17931796
sub_add_reg, select_to_minmax, redundant_binop_in_equality,
17941797
fsub_to_fneg, commute_constant_to_rhs, match_ands, match_ors,
17951798
combine_concat_vector, double_icmp_zero_and_or_combine, match_addos,
1796-
sext_trunc, zext_trunc, combine_shuffle_concat,
1797-
push_freeze_to_prevent_poison_from_propagating]>;
1799+
sext_trunc, zext_trunc, combine_shuffle_concat]>;
17981800

17991801
// A combine group used to for prelegalizer combiners at -O0. The combines in
18001802
// this group have been selected based on experiments to balance code size and

llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,18 +265,24 @@ bool CombinerHelper::matchFreezeOfSingleMaybePoisonOperand(
265265
}
266266
}
267267

268-
cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
269-
270268
// Eliminate freeze if all operands are guaranteed non-poison.
271269
if (!MaybePoisonOperand) {
272-
MatchInfo = [=](MachineIRBuilder &B) { MRI.replaceRegWith(DstOp, OrigOp); };
270+
MatchInfo = [=](MachineIRBuilder &B) {
271+
Observer.changingInstr(*OrigDef);
272+
cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
273+
Observer.changedInstr(*OrigDef);
274+
B.buildCopy(DstOp, OrigOp);
275+
};
273276
return true;
274277
}
275278

276279
Register MaybePoisonOperandReg = MaybePoisonOperand->getReg();
277280
LLT MaybePoisonOperandRegTy = MRI.getType(MaybePoisonOperandReg);
278281

279282
MatchInfo = [=](MachineIRBuilder &B) mutable {
283+
Observer.changingInstr(*OrigDef);
284+
cast<GenericMachineInstr>(OrigDef)->dropPoisonGeneratingFlags();
285+
Observer.changedInstr(*OrigDef);
280286
B.setInsertPt(*OrigDef->getParent(), OrigDef->getIterator());
281287
auto Freeze = B.buildFreeze(MaybePoisonOperandRegTy, MaybePoisonOperandReg);
282288
replaceRegOpWith(

llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -144,59 +144,6 @@ bool CombinerHelper::matchExtractVectorElementWithDifferentIndices(
144144
return false;
145145
}
146146

147-
bool CombinerHelper::matchExtractVectorElementWithFreeze(
148-
const MachineOperand &MO, BuildFnTy &MatchInfo) {
149-
MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);
150-
GExtractVectorElement *Extract = cast<GExtractVectorElement>(Root);
151-
152-
Register Vector = Extract->getVectorReg();
153-
154-
//
155-
// %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
156-
// %freeze:_(<2 x s32>) = G_FREEZE %bv(<2 x s32>)
157-
// %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
158-
//
159-
// -->
160-
//
161-
// %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32)
162-
// %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64)
163-
// %freeze:_(s32) = G_FREEZE %extract(s32)
164-
//
165-
//
166-
167-
// For G_FREEZE, the input and the output types are identical. Moving the
168-
// freeze from the Vector into the front of the extract preserves the freeze
169-
// semantics. The result is still freeze'd. Furthermore, the Vector register
170-
// becomes easier to analyze. A build vector could have been hidden behind the
171-
// freeze.
172-
173-
// We expect a freeze on the Vector register.
174-
GFreeze *Freeze = getOpcodeDef<GFreeze>(Vector, MRI);
175-
if (!Freeze)
176-
return false;
177-
178-
Register Dst = Extract->getReg(0);
179-
LLT DstTy = MRI.getType(Dst);
180-
181-
// We first have to check for one-use and legality of the freeze.
182-
// The type of the extractVectorElement did not change.
183-
if (!MRI.hasOneNonDBGUse(Freeze->getReg(0)) ||
184-
!isLegalOrBeforeLegalizer({TargetOpcode::G_FREEZE, {DstTy}}))
185-
return false;
186-
187-
Register Index = Extract->getIndexReg();
188-
189-
// We move the freeze from the Vector register in front of the
190-
// extractVectorElement.
191-
MatchInfo = [=](MachineIRBuilder &B) {
192-
auto Extract =
193-
B.buildExtractVectorElement(DstTy, Freeze->getSourceReg(), Index);
194-
B.buildFreeze(Dst, Extract);
195-
};
196-
197-
return true;
198-
}
199-
200147
bool CombinerHelper::matchExtractVectorElementWithBuildVector(
201148
const MachineOperand &MO, BuildFnTy &MatchInfo) {
202149
MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI);

llvm/lib/CodeGen/GlobalISel/Utils.cpp

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,39 @@ bool llvm::isPreISelGenericFloatingPointOpcode(unsigned Opc) {
17241724
}
17251725
}
17261726

1727+
/// Shifts return poison if shiftwidth is larger than the bitwidth.
1728+
static bool shiftAmountKnownInRange(Register ShiftAmount,
1729+
const MachineRegisterInfo &MRI) {
1730+
LLT Ty = MRI.getType(ShiftAmount);
1731+
1732+
if (Ty.isScalableVector())
1733+
return false; // Can't tell, just return false to be safe
1734+
1735+
if (Ty.isScalar()) {
1736+
std::optional<ValueAndVReg> Val =
1737+
getIConstantVRegValWithLookThrough(ShiftAmount, MRI);
1738+
if (!Val)
1739+
return false;
1740+
return Val->Value.ult(Ty.getScalarSizeInBits());
1741+
}
1742+
1743+
GBuildVector *BV = getOpcodeDef<GBuildVector>(ShiftAmount, MRI);
1744+
if (!BV)
1745+
return false;
1746+
1747+
unsigned Sources = BV->getNumSources();
1748+
for (unsigned I = 0; I < Sources; ++I) {
1749+
std::optional<ValueAndVReg> Val =
1750+
getIConstantVRegValWithLookThrough(BV->getSourceReg(I), MRI);
1751+
if (!Val)
1752+
return false;
1753+
if (!Val->Value.ult(Ty.getScalarSizeInBits()))
1754+
return false;
1755+
}
1756+
1757+
return true;
1758+
}
1759+
17271760
namespace {
17281761
enum class UndefPoisonKind {
17291762
PoisonOnly = (1 << 0),
@@ -1732,11 +1765,11 @@ enum class UndefPoisonKind {
17321765
};
17331766
}
17341767

1735-
[[maybe_unused]] static bool includesPoison(UndefPoisonKind Kind) {
1768+
static bool includesPoison(UndefPoisonKind Kind) {
17361769
return (unsigned(Kind) & unsigned(UndefPoisonKind::PoisonOnly)) != 0;
17371770
}
17381771

1739-
[[maybe_unused]] static bool includesUndef(UndefPoisonKind Kind) {
1772+
static bool includesUndef(UndefPoisonKind Kind) {
17401773
return (unsigned(Kind) & unsigned(UndefPoisonKind::UndefOnly)) != 0;
17411774
}
17421775

@@ -1745,18 +1778,55 @@ static bool canCreateUndefOrPoison(Register Reg, const MachineRegisterInfo &MRI,
17451778
UndefPoisonKind Kind) {
17461779
MachineInstr *RegDef = MRI.getVRegDef(Reg);
17471780

1748-
if (auto *GMI = dyn_cast<GenericMachineInstr>(RegDef)) {
1749-
if (ConsiderFlagsAndMetadata && includesPoison(Kind) &&
1750-
GMI->hasPoisonGeneratingFlags())
1751-
return true;
1752-
} else {
1753-
// Conservatively return true.
1754-
return true;
1755-
}
1781+
if (ConsiderFlagsAndMetadata && includesPoison(Kind))
1782+
if (auto *GMI = dyn_cast<GenericMachineInstr>(RegDef))
1783+
if (GMI->hasPoisonGeneratingFlags())
1784+
return true;
17561785

1786+
// Check whether opcode is a poison/undef-generating operation.
17571787
switch (RegDef->getOpcode()) {
17581788
case TargetOpcode::G_FREEZE:
1789+
case TargetOpcode::G_BUILD_VECTOR:
1790+
case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
17591791
return false;
1792+
case TargetOpcode::G_SHL:
1793+
case TargetOpcode::G_ASHR:
1794+
case TargetOpcode::G_LSHR:
1795+
return includesPoison(Kind) &&
1796+
!shiftAmountKnownInRange(RegDef->getOperand(2).getReg(), MRI);
1797+
case TargetOpcode::G_FPTOSI:
1798+
case TargetOpcode::G_FPTOUI:
1799+
// fptosi/ui yields poison if the resulting value does not fit in the
1800+
// destination type.
1801+
return true;
1802+
case TargetOpcode::G_CTLZ:
1803+
case TargetOpcode::G_CTTZ:
1804+
case TargetOpcode::G_ABS:
1805+
case TargetOpcode::G_CTPOP:
1806+
case TargetOpcode::G_BSWAP:
1807+
case TargetOpcode::G_BITREVERSE:
1808+
case TargetOpcode::G_FSHL:
1809+
case TargetOpcode::G_FSHR:
1810+
case TargetOpcode::G_SMAX:
1811+
case TargetOpcode::G_SMIN:
1812+
case TargetOpcode::G_UMAX:
1813+
case TargetOpcode::G_UMIN:
1814+
case TargetOpcode::G_PTRMASK:
1815+
case TargetOpcode::G_SADDO:
1816+
case TargetOpcode::G_SSUBO:
1817+
case TargetOpcode::G_UADDO:
1818+
case TargetOpcode::G_USUBO:
1819+
case TargetOpcode::G_SMULO:
1820+
case TargetOpcode::G_UMULO:
1821+
case TargetOpcode::G_SADDSAT:
1822+
case TargetOpcode::G_UADDSAT:
1823+
case TargetOpcode::G_SSUBSAT:
1824+
case TargetOpcode::G_USUBSAT:
1825+
return false;
1826+
case TargetOpcode::G_SSHLSAT:
1827+
case TargetOpcode::G_USHLSAT:
1828+
return includesPoison(Kind) &&
1829+
!shiftAmountKnownInRange(RegDef->getOperand(2).getReg(), MRI);
17601830
default:
17611831
return !isa<GCastOp>(RegDef) && !isa<GBinOp>(RegDef);
17621832
}
@@ -1776,6 +1846,18 @@ static bool isGuaranteedNotToBeUndefOrPoison(Register Reg,
17761846
return true;
17771847
case TargetOpcode::G_IMPLICIT_DEF:
17781848
return !includesUndef(Kind);
1849+
case TargetOpcode::G_CONSTANT:
1850+
case TargetOpcode::G_FCONSTANT:
1851+
return true;
1852+
case TargetOpcode::G_BUILD_VECTOR: {
1853+
GBuildVector *BV = cast<GBuildVector>(RegDef);
1854+
unsigned NumSources = BV->getNumSources();
1855+
for (unsigned I = 0; I < NumSources; ++I)
1856+
if (!::isGuaranteedNotToBeUndefOrPoison(BV->getSourceReg(I), MRI,
1857+
Depth + 1, Kind))
1858+
return false;
1859+
return true;
1860+
}
17791861
default: {
17801862
auto MOCheck = [&](const MachineOperand &MO) {
17811863
if (!MO.isReg())

llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ body: |
361361
; CHECK-NEXT: {{ $}}
362362
; CHECK-NEXT: %vec:_(<2 x s64>) = COPY $q0
363363
; CHECK-NEXT: %idx:_(s64) = COPY $x1
364-
; CHECK-NEXT: [[EVEC:%[0-9]+]]:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s64)
365-
; CHECK-NEXT: %extract:_(s64) = G_FREEZE [[EVEC]]
364+
; CHECK-NEXT: %fvec:_(<2 x s64>) = G_FREEZE %vec
365+
; CHECK-NEXT: %extract:_(s64) = G_EXTRACT_VECTOR_ELT %fvec(<2 x s64>), %idx(s64)
366366
; CHECK-NEXT: $x0 = COPY %extract(s64)
367367
; CHECK-NEXT: RET_ReallyLR implicit $x0
368368
%vec:_(<2 x s64>) = COPY $q0

0 commit comments

Comments
 (0)