Skip to content

[GISel] Combine compare of bitfield extracts or'd together. #146055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: users/pierre-vh/dag-combine-workitems-intrinsics
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ class CombinerHelper {
/// KnownBits information.
bool matchICmpToLHSKnownBits(MachineInstr &MI, BuildFnTy &MatchInfo) const;

bool combineMergedBFXCompare(MachineInstr &MI) const;

/// \returns true if (and (or x, c1), c2) can be replaced with (and x, c2)
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo) const;

Expand Down
11 changes: 10 additions & 1 deletion llvm/include/llvm/Target/GlobalISel/Combine.td
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,14 @@ def double_icmp_zero_or_combine: GICombineRule<
(G_ICMP $root, $p, $ordst, 0))
>;

// Transform ((X | (G_UBFX X, ...) | ...) == 0) (or != 0)
// into a compare of a extract/mask of X
def icmp_merged_bfx_combine: GICombineRule<
(defs root:$root),
(combine (G_ICMP $dst, $p, $src, 0):$root,
[{ return Helper.combineMergedBFXCompare(*${root}); }])
>;

def and_or_disjoint_mask : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_AND):$root,
Expand Down Expand Up @@ -2052,7 +2060,8 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
fsub_to_fneg, commute_constant_to_rhs, match_ands, match_ors,
simplify_neg_minmax, combine_concat_vector,
sext_trunc, zext_trunc, prefer_sign_combines, shuffle_combines,
combine_use_vector_truncate, merge_combines, overflow_combines]>;
combine_use_vector_truncate, merge_combines, overflow_combines,
icmp_merged_bfx_combine]>;

// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
Expand Down
89 changes: 89 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/CombinerHelperCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,92 @@ bool CombinerHelper::matchCanonicalizeFCmp(const MachineInstr &MI,

return false;
}

bool CombinerHelper::combineMergedBFXCompare(MachineInstr &MI) const {
const GICmp *Cmp = cast<GICmp>(&MI);

ICmpInst::Predicate CC = Cmp->getCond();
if (CC != CmpInst::ICMP_EQ && CC != CmpInst::ICMP_NE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CmpInst::isEquality

return false;

Register CmpLHS = Cmp->getLHSReg();
Register CmpRHS = Cmp->getRHSReg();

LLT OpTy = MRI.getType(CmpLHS);
if (!OpTy.isScalar() || OpTy.isPointer())
return false;

assert(isZeroOrZeroSplat(CmpRHS, /*AllowUndefs=*/false));

Register Src;
const auto IsSrc = [&](Register R) {
if (!Src) {
Src = R;
return true;
}

return Src == R;
};

MachineInstr *CmpLHSDef = MRI.getVRegDef(CmpLHS);
if (CmpLHSDef->getOpcode() != TargetOpcode::G_OR)
return false;

APInt PartsMask(OpTy.getSizeInBits(), 0);
SmallVector<MachineInstr *> Worklist = {CmpLHSDef};
while (!Worklist.empty()) {
MachineInstr *Cur = Worklist.pop_back_val();

Register Dst = Cur->getOperand(0).getReg();
if (!MRI.hasOneUse(Dst) && Dst != Src)
return false;

if (Cur->getOpcode() == TargetOpcode::G_OR) {
Worklist.push_back(MRI.getVRegDef(Cur->getOperand(1).getReg()));
Worklist.push_back(MRI.getVRegDef(Cur->getOperand(2).getReg()));
continue;
}

if (Cur->getOpcode() == TargetOpcode::G_UBFX) {
Register Op = Cur->getOperand(1).getReg();
Register Width = Cur->getOperand(2).getReg();
Register Off = Cur->getOperand(3).getReg();

auto WidthCst = getIConstantVRegVal(Width, MRI);
auto OffCst = getIConstantVRegVal(Off, MRI);
if (!WidthCst || !OffCst || !IsSrc(Op))
return false;

unsigned Start = OffCst->getZExtValue();
unsigned End = Start + WidthCst->getZExtValue();
if (End > OpTy.getScalarSizeInBits())
return false;
PartsMask.setBits(Start, End);
continue;
}

if (Cur->getOpcode() == TargetOpcode::G_AND) {
Register LHS = Cur->getOperand(1).getReg();
Register RHS = Cur->getOperand(2).getReg();

auto MaskCst = getIConstantVRegVal(RHS, MRI);
if (!MaskCst || !MaskCst->isMask() || !IsSrc(LHS))
return false;

PartsMask |= *MaskCst;
continue;
}

return false;
}

if (!PartsMask.isMask() || !Src)
return false;

assert(OpTy == MRI.getType(Src) && "Ignored a type casting operation?");
auto MaskedSrc =
Builder.buildAnd(OpTy, Src, Builder.buildConstant(OpTy, PartsMask));
Builder.buildICmp(CC, Cmp->getReg(0), MaskedSrc, CmpRHS, Cmp->getFlags());
MI.eraseFromParent();
return true;
}
Loading
Loading