[llvm] [ISel] Introduce `llvm.pext` and `llvm.pdep` intrinsics (PR #200570)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 2 23:45:37 PDT 2026
================
@@ -8962,6 +8962,82 @@ SDValue TargetLowering::expandCLMUL(SDNode *Node, SelectionDAG &DAG) const {
llvm_unreachable("Expected CLMUL, CLMULR, or CLMULH");
}
+SDValue TargetLowering::expandPEXT(SDNode *Node, SelectionDAG &DAG) const {
+ SDLoc DL(Node);
+ EVT VT = Node->getValueType(0);
+ SDValue Val = Node->getOperand(0);
+ SDValue Msk = Node->getOperand(1);
+ unsigned BW = VT.getScalarSizeInBits();
+
+ // Hacker's Delight §7-4: Compress, or Generalized Extract
+ SDValue X = DAG.getNode(ISD::AND, DL, VT, Val, Msk);
+ SDValue M = Msk;
+ SDValue One = DAG.getShiftAmountConstant(1, VT, DL);
+ SDValue Mk = DAG.getNode(ISD::SHL, DL, VT, DAG.getNOT(DL, M, VT), One);
+
+ // Repeatedly compute which bits would shift to the right by an odd amount,
+ // shift all such bits in parallel using a mask, and double the shift amount.
+ for (unsigned I = 1; I < BW; I <<= 1) {
+ // This expands the "parallel prefix" operation to clmul(Mk, ~0).
+ SDValue Mp =
+ DAG.getNode(ISD::CLMUL, DL, VT, Mk, DAG.getAllOnesConstant(DL, VT));
+ SDValue Mv = DAG.getNode(ISD::AND, DL, VT, Mp, M);
+ SDValue ShiftI = DAG.getShiftAmountConstant(I, VT, DL);
+ SDValue MvS = DAG.getNode(ISD::SRL, DL, VT, Mv, ShiftI);
+ M = DAG.getNode(ISD::OR, DL, VT, DAG.getNode(ISD::XOR, DL, VT, M, Mv), MvS);
+ SDValue T = DAG.getNode(ISD::AND, DL, VT, X, Mv);
+ SDValue TS = DAG.getNode(ISD::SRL, DL, VT, T, ShiftI);
+ X = DAG.getNode(ISD::OR, DL, VT, DAG.getNode(ISD::XOR, DL, VT, X, T), TS);
+ Mk = DAG.getNode(ISD::AND, DL, VT, Mk, DAG.getNOT(DL, Mp, VT));
+ }
+
+ return X;
+}
+
+SDValue TargetLowering::expandPDEP(SDNode *Node, SelectionDAG &DAG) const {
+ SDLoc DL(Node);
+ EVT VT = Node->getValueType(0);
+ SDValue Val = Node->getOperand(0);
+ SDValue Msk = Node->getOperand(1);
+ unsigned BW = VT.getScalarSizeInBits();
+
+ // Hacker's Delight §7-5: Expand, or Generalized Insert.
+ unsigned LogBW = Log2_32_Ceil(BW);
+ SmallVector<SDValue, 8> MvArray(LogBW);
+ SDValue One = DAG.getShiftAmountConstant(1, VT, DL);
+ SDValue Mc = Msk;
+ SDValue Mk = DAG.getNode(ISD::SHL, DL, VT, DAG.getNOT(DL, Msk, VT), One);
+
+ // First pass: compute move masks for each power of two that a bit moves by.
+ for (unsigned S = 0; S < LogBW; ++S) {
+ unsigned ShiftS = 1u << S;
+ // This expands the "parallel prefix" operation to clmul(Mk, ~0).
+ SDValue Mp =
+ DAG.getNode(ISD::CLMUL, DL, VT, Mk, DAG.getAllOnesConstant(DL, VT));
+ SDValue Mv = DAG.getNode(ISD::AND, DL, VT, Mp, Mc);
+ MvArray[S] = Mv;
+ SDValue McXorMv = DAG.getNode(ISD::XOR, DL, VT, Mc, Mv);
----------------
topperc wrote:
I don't really like creating dead nodes on the last iteration of the loop.
https://github.com/llvm/llvm-project/pull/200570
More information about the llvm-commits
mailing list