-
Notifications
You must be signed in to change notification settings - Fork 18.1k
[X86] Ensure a (vXi1 bitcast(iX Mask)) memory mask is canonicalised for extension before it might get split by legalisation #175769
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
Changes from 3 commits
f500548
12bd91b
250d1d7
5a19bfa
e281692
974c7e5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53503,6 +53503,23 @@ static SDValue combineLoad(SDNode *N, SelectionDAG &DAG, | |
| return SDValue(); | ||
| } | ||
|
|
||
| // Attempt to convert a (vXi1 bitcast(iX Mask)) mask before it might get split | ||
| // by legalization. | ||
| static SDValue canonicalizeBoolMask(unsigned Opcode, EVT VT, SDValue Mask, | ||
| const SDLoc &DL, SelectionDAG &DAG, | ||
| TargetLowering::DAGCombinerInfo &DCI, | ||
| const X86Subtarget &Subtarget) { | ||
| if (!DCI.isBeforeLegalizeOps() || Mask.getOpcode() != ISD::BITCAST || | ||
| Mask.getScalarValueSizeInBits() != 1 || Subtarget.hasAVX512() || | ||
| !DAG.getTargetLoweringInfo().isOperationLegalOrCustom(Opcode, VT)) | ||
| return SDValue(); | ||
|
|
||
| EVT ExtMaskVT = VT.changeVectorElementTypeToInteger(); | ||
| assert(ExtMaskVT.bitsGT(Mask.getValueType()) && "Unexpected extension type"); | ||
| return combineToExtendBoolVectorInReg(ISD::SIGN_EXTEND, DL, ExtMaskVT, Mask, | ||
| DAG, DCI, Subtarget); | ||
| } | ||
|
|
||
| /// If V is a build vector of boolean constants and exactly one of those | ||
| /// constants is true, return the operand index of that true element. | ||
| /// Otherwise, return -1. | ||
|
|
@@ -53679,12 +53696,25 @@ static SDValue combineMaskedLoad(SDNode *N, SelectionDAG &DAG, | |
| return Blend; | ||
| } | ||
|
|
||
| EVT VT = Mld->getValueType(0); | ||
| SDValue Mask = Mld->getMask(); | ||
| const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | ||
| SDLoc DL(N); | ||
|
|
||
| // Attempt to convert a (vXi1 bitcast(iX Mask)) mask before it might get split | ||
| // by legalization. | ||
| if (SDValue NewMask = | ||
| canonicalizeBoolMask(ISD::MLOAD, VT, Mask, DL, DAG, DCI, Subtarget)) { | ||
| NewMask = DAG.getNode(ISD::TRUNCATE, DL, Mask.getValueType(), NewMask); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be moved into |
||
| return DAG.getMaskedLoad(VT, DL, Mld->getChain(), Mld->getBasePtr(), | ||
| Mld->getOffset(), NewMask, Mld->getPassThru(), | ||
| Mld->getMemoryVT(), Mld->getMemOperand(), | ||
| Mld->getAddressingMode(), Mld->getExtensionType()); | ||
| } | ||
|
|
||
| // If the mask value has been legalized to a non-boolean vector, try to | ||
| // simplify ops leading up to it. We only demand the MSB of each lane. | ||
| SDValue Mask = Mld->getMask(); | ||
| if (Mask.getScalarValueSizeInBits() != 1) { | ||
| EVT VT = Mld->getValueType(0); | ||
| const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | ||
| APInt DemandedBits(APInt::getSignMask(VT.getScalarSizeInBits())); | ||
| if (TLI.SimplifyDemandedBits(Mask, DemandedBits, DCI)) { | ||
| if (N->getOpcode() != ISD::DELETED_NODE) | ||
|
|
@@ -53694,8 +53724,8 @@ static SDValue combineMaskedLoad(SDNode *N, SelectionDAG &DAG, | |
| if (SDValue NewMask = | ||
| TLI.SimplifyMultipleUseDemandedBits(Mask, DemandedBits, DAG)) | ||
| return DAG.getMaskedLoad( | ||
| VT, SDLoc(N), Mld->getChain(), Mld->getBasePtr(), Mld->getOffset(), | ||
| NewMask, Mld->getPassThru(), Mld->getMemoryVT(), Mld->getMemOperand(), | ||
| VT, DL, Mld->getChain(), Mld->getBasePtr(), Mld->getOffset(), NewMask, | ||
| Mld->getPassThru(), Mld->getMemoryVT(), Mld->getMemOperand(), | ||
| Mld->getAddressingMode(), Mld->getExtensionType()); | ||
| } | ||
|
|
||
|
|
@@ -53785,6 +53815,17 @@ static SDValue combineMaskedStore(SDNode *N, SelectionDAG &DAG, | |
| return SDValue(); | ||
| } | ||
|
|
||
| // Attempt to convert a (vXi1 bitcast(iX Mask)) mask before it might get split | ||
| // by legalization. | ||
| if (SDValue NewMask = canonicalizeBoolMask(ISD::MSTORE, VT, Mask, DL, DAG, | ||
| DCI, Subtarget)) { | ||
| NewMask = DAG.getNode(ISD::TRUNCATE, DL, Mask.getValueType(), NewMask); | ||
| return DAG.getMaskedStore(Mst->getChain(), SDLoc(N), Mst->getValue(), | ||
| Mst->getBasePtr(), Mst->getOffset(), NewMask, | ||
| Mst->getMemoryVT(), Mst->getMemOperand(), | ||
| Mst->getAddressingMode()); | ||
| } | ||
|
|
||
| // If the mask value has been legalized to a non-boolean vector, try to | ||
| // simplify ops leading up to it. We only demand the MSB of each lane. | ||
| if (Mask.getScalarValueSizeInBits() != 1) { | ||
|
|
@@ -57398,35 +57439,35 @@ static SDValue combineX86GatherScatter(SDNode *N, SelectionDAG &DAG, | |
| } | ||
|
|
||
| static SDValue rebuildGatherScatter(MaskedGatherScatterSDNode *GorS, | ||
| SDValue Index, SDValue Base, SDValue Scale, | ||
| SelectionDAG &DAG) { | ||
| SDValue Index, SDValue Base, SDValue Mask, | ||
| SDValue Scale, SelectionDAG &DAG) { | ||
| SDLoc DL(GorS); | ||
|
|
||
| if (auto *Gather = dyn_cast<MaskedGatherSDNode>(GorS)) { | ||
| SDValue Ops[] = { Gather->getChain(), Gather->getPassThru(), | ||
| Gather->getMask(), Base, Index, Scale } ; | ||
| return DAG.getMaskedGather(Gather->getVTList(), | ||
| Gather->getMemoryVT(), DL, Ops, | ||
| Gather->getMemOperand(), | ||
| SDValue Ops[] = { | ||
| Gather->getChain(), Gather->getPassThru(), Mask, Base, Index, Scale}; | ||
| return DAG.getMaskedGather(Gather->getVTList(), Gather->getMemoryVT(), DL, | ||
| Ops, Gather->getMemOperand(), | ||
| Gather->getIndexType(), | ||
| Gather->getExtensionType()); | ||
| } | ||
| auto *Scatter = cast<MaskedScatterSDNode>(GorS); | ||
| SDValue Ops[] = { Scatter->getChain(), Scatter->getValue(), | ||
| Scatter->getMask(), Base, Index, Scale }; | ||
| return DAG.getMaskedScatter(Scatter->getVTList(), | ||
| Scatter->getMemoryVT(), DL, | ||
| SDValue Ops[] = { | ||
| Scatter->getChain(), Scatter->getValue(), Mask, Base, Index, Scale}; | ||
| return DAG.getMaskedScatter(Scatter->getVTList(), Scatter->getMemoryVT(), DL, | ||
| Ops, Scatter->getMemOperand(), | ||
| Scatter->getIndexType(), | ||
| Scatter->isTruncatingStore()); | ||
| } | ||
|
|
||
| static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | ||
| TargetLowering::DAGCombinerInfo &DCI) { | ||
| TargetLowering::DAGCombinerInfo &DCI, | ||
| const X86Subtarget &Subtarget) { | ||
| SDLoc DL(N); | ||
| auto *GorS = cast<MaskedGatherScatterSDNode>(N); | ||
| SDValue Index = GorS->getIndex(); | ||
| SDValue Base = GorS->getBasePtr(); | ||
| SDValue Mask = GorS->getMask(); | ||
| SDValue Scale = GorS->getScale(); | ||
| EVT IndexVT = Index.getValueType(); | ||
| EVT IndexSVT = IndexVT.getVectorElementType(); | ||
|
|
@@ -57460,7 +57501,8 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| Index.getOperand(0), NewShAmt); | ||
| SDValue NewScale = | ||
| DAG.getConstant(ScaleAmt * 2, DL, Scale.getValueType()); | ||
| return rebuildGatherScatter(GorS, NewIndex, Base, NewScale, DAG); | ||
| return rebuildGatherScatter(GorS, NewIndex, Base, Mask, NewScale, | ||
| DAG); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -57478,7 +57520,7 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| // a split. | ||
| if (SDValue TruncIndex = | ||
| DAG.FoldConstantArithmetic(ISD::TRUNCATE, DL, NewVT, Index)) | ||
| return rebuildGatherScatter(GorS, TruncIndex, Base, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, TruncIndex, Base, Mask, Scale, DAG); | ||
|
|
||
| // Shrink any sign/zero extends from 32 or smaller to larger than 32 if | ||
| // there are sufficient sign bits. Only do this before legalize types to | ||
|
|
@@ -57487,13 +57529,13 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| Index.getOpcode() == ISD::ZERO_EXTEND) && | ||
| Index.getOperand(0).getScalarValueSizeInBits() <= 32) { | ||
| Index = DAG.getNode(ISD::TRUNCATE, DL, NewVT, Index); | ||
| return rebuildGatherScatter(GorS, Index, Base, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, Index, Base, Mask, Scale, DAG); | ||
| } | ||
|
|
||
| // Shrink if we remove an illegal type. | ||
| if (!TLI.isTypeLegal(Index.getValueType()) && TLI.isTypeLegal(NewVT)) { | ||
| Index = DAG.getNode(ISD::TRUNCATE, DL, NewVT, Index); | ||
| return rebuildGatherScatter(GorS, Index, Base, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, Index, Base, Mask, Scale, DAG); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -57518,13 +57560,15 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| SDValue NewBase = DAG.getNode(ISD::ADD, DL, PtrVT, Base, | ||
| DAG.getConstant(Adder, DL, PtrVT)); | ||
| SDValue NewIndex = Index.getOperand(1 - I); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Mask, Scale, | ||
| DAG); | ||
| } | ||
| // For non-constant cases, limit this to non-scaled cases. | ||
| if (ScaleAmt == 1) { | ||
| SDValue NewBase = DAG.getNode(ISD::ADD, DL, PtrVT, Base, Splat); | ||
| SDValue NewIndex = Index.getOperand(1 - I); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Mask, Scale, | ||
| DAG); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -57539,7 +57583,8 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| SDValue NewIndex = DAG.getNode(ISD::ADD, DL, IndexVT, | ||
| Index.getOperand(1 - I), Splat); | ||
| SDValue NewBase = DAG.getConstant(0, DL, PtrVT); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, NewIndex, NewBase, Mask, Scale, | ||
| DAG); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -57550,12 +57595,20 @@ static SDValue combineGatherScatter(SDNode *N, SelectionDAG &DAG, | |
| MVT EltVT = IndexWidth > 32 ? MVT::i64 : MVT::i32; | ||
| IndexVT = IndexVT.changeVectorElementType(*DAG.getContext(), EltVT); | ||
| Index = DAG.getSExtOrTrunc(Index, DL, IndexVT); | ||
| return rebuildGatherScatter(GorS, Index, Base, Scale, DAG); | ||
| return rebuildGatherScatter(GorS, Index, Base, Mask, Scale, DAG); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why only limit to gather here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're only targeting AVX2, as it has no mask registers or scatter instruction
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've removed the explicit Opcode check for ISD::MGATHER and now rely on canonicalizeBoolMask to early-out because ISD::MSCATTER isn't legal/custom on pre-AVX512 targets |
||
|
|
||
| // Attempt to convert a (vXi1 bitcast(iX Mask)) mask before it might get | ||
| // split by legalization. | ||
| if (SDValue NewMask = | ||
| canonicalizeBoolMask(GorS->getOpcode(), N->getValueType(0), Mask, | ||
| DL, DAG, DCI, Subtarget)) { | ||
| NewMask = DAG.getNode(ISD::TRUNCATE, DL, Mask.getValueType(), NewMask); | ||
| return rebuildGatherScatter(GorS, Index, Base, NewMask, Scale, DAG); | ||
| } | ||
| } | ||
|
|
||
| // With vector masks we only demand the upper bit of the mask. | ||
| SDValue Mask = GorS->getMask(); | ||
| if (Mask.getScalarValueSizeInBits() != 1) { | ||
| APInt DemandedMask(APInt::getSignMask(Mask.getScalarValueSizeInBits())); | ||
| if (TLI.SimplifyDemandedBits(Mask, DemandedMask, DCI)) { | ||
|
|
@@ -61700,7 +61753,7 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N, | |
| case X86ISD::MGATHER: | ||
| case X86ISD::MSCATTER: return combineX86GatherScatter(N, DAG, DCI); | ||
| case ISD::MGATHER: | ||
| case ISD::MSCATTER: return combineGatherScatter(N, DAG, DCI); | ||
| case ISD::MSCATTER: return combineGatherScatter(N, DAG, DCI, Subtarget); | ||
| case X86ISD::PCMPEQ: | ||
| case X86ISD::PCMPGT: return combineVectorCompare(N, DAG, Subtarget); | ||
| case X86ISD::PMULDQ: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check
NewMaskbefore truncate?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch