@@ -157,6 +157,12 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
157
157
158
158
// SIMD-specific configuration
159
159
if (Subtarget->hasSIMD128 ()) {
160
+ // Combine vector mask reductions into alltrue/anytrue
161
+ setTargetDAGCombine (ISD::SETCC);
162
+
163
+ // Convert vector to integer bitcasts to bitmask
164
+ setTargetDAGCombine (ISD::BITCAST);
165
+
160
166
// Hoist bitcasts out of shuffles
161
167
setTargetDAGCombine (ISD::VECTOR_SHUFFLE);
162
168
@@ -258,6 +264,12 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
258
264
// But saturating fp_to_int converstions are
259
265
for (auto Op : {ISD::FP_TO_SINT_SAT, ISD::FP_TO_UINT_SAT})
260
266
setOperationAction (Op, MVT::v4i32, Custom);
267
+
268
+ // Support vector extending
269
+ for (auto T : MVT::integer_fixedlen_vector_valuetypes ()) {
270
+ setOperationAction (ISD::SIGN_EXTEND_VECTOR_INREG, T, Custom);
271
+ setOperationAction (ISD::ZERO_EXTEND_VECTOR_INREG, T, Custom);
272
+ }
261
273
}
262
274
263
275
// As a special case, these operators use the type to mean the type to
@@ -1374,6 +1386,11 @@ void WebAssemblyTargetLowering::ReplaceNodeResults(
1374
1386
// SIGN_EXTEND_INREG, but for non-vector sign extends the result might be an
1375
1387
// illegal type.
1376
1388
break ;
1389
+ case ISD::SIGN_EXTEND_VECTOR_INREG:
1390
+ case ISD::ZERO_EXTEND_VECTOR_INREG:
1391
+ // Do not add any results, signifying that N should not be custom lowered.
1392
+ // EXTEND_VECTOR_INREG is implemented for some vectors, but not all.
1393
+ break ;
1377
1394
default :
1378
1395
llvm_unreachable (
1379
1396
" ReplaceNodeResults not implemented for this op for WebAssembly!" );
@@ -1424,6 +1441,9 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op,
1424
1441
return LowerIntrinsic (Op, DAG);
1425
1442
case ISD::SIGN_EXTEND_INREG:
1426
1443
return LowerSIGN_EXTEND_INREG (Op, DAG);
1444
+ case ISD::ZERO_EXTEND_VECTOR_INREG:
1445
+ case ISD::SIGN_EXTEND_VECTOR_INREG:
1446
+ return LowerEXTEND_VECTOR_INREG (Op, DAG);
1427
1447
case ISD::BUILD_VECTOR:
1428
1448
return LowerBUILD_VECTOR (Op, DAG);
1429
1449
case ISD::VECTOR_SHUFFLE:
@@ -1877,6 +1897,48 @@ WebAssemblyTargetLowering::LowerSIGN_EXTEND_INREG(SDValue Op,
1877
1897
Op.getOperand (1 ));
1878
1898
}
1879
1899
1900
+ SDValue
1901
+ WebAssemblyTargetLowering::LowerEXTEND_VECTOR_INREG (SDValue Op,
1902
+ SelectionDAG &DAG) const {
1903
+ SDLoc DL (Op);
1904
+ EVT VT = Op.getValueType ();
1905
+ SDValue Src = Op.getOperand (0 );
1906
+ EVT SrcVT = Src.getValueType ();
1907
+
1908
+ if (SrcVT.getVectorElementType () == MVT::i1 ||
1909
+ SrcVT.getVectorElementType () == MVT::i64)
1910
+ return SDValue ();
1911
+
1912
+ assert (VT.getScalarSizeInBits () % SrcVT.getScalarSizeInBits () == 0 &&
1913
+ " Unexpected extension factor." );
1914
+ unsigned Scale = VT.getScalarSizeInBits () / SrcVT.getScalarSizeInBits ();
1915
+
1916
+ if (Scale != 2 && Scale != 4 && Scale != 8 )
1917
+ return SDValue ();
1918
+
1919
+ unsigned Ext;
1920
+ switch (Op.getOpcode ()) {
1921
+ case ISD::ZERO_EXTEND_VECTOR_INREG:
1922
+ Ext = WebAssemblyISD::EXTEND_LOW_U;
1923
+ break ;
1924
+ case ISD::SIGN_EXTEND_VECTOR_INREG:
1925
+ Ext = WebAssemblyISD::EXTEND_LOW_S;
1926
+ break ;
1927
+ }
1928
+
1929
+ SDValue Ret = Src;
1930
+ while (Scale != 1 ) {
1931
+ Ret = DAG.getNode (Ext, DL,
1932
+ Ret.getValueType ()
1933
+ .widenIntegerVectorElementType (*DAG.getContext ())
1934
+ .getHalfNumVectorElementsVT (*DAG.getContext ()),
1935
+ Ret);
1936
+ Scale /= 2 ;
1937
+ }
1938
+ assert (Ret.getValueType () == VT);
1939
+ return Ret;
1940
+ }
1941
+
1880
1942
static SDValue LowerConvertLow (SDValue Op, SelectionDAG &DAG) {
1881
1943
SDLoc DL (Op);
1882
1944
if (Op.getValueType () != MVT::v2f64)
@@ -2692,12 +2754,90 @@ static SDValue performTruncateCombine(SDNode *N,
2692
2754
return truncateVectorWithNARROW (OutVT, In, DL, DAG);
2693
2755
}
2694
2756
2757
+ static SDValue performBitcastCombine (SDNode *N,
2758
+ TargetLowering::DAGCombinerInfo &DCI) {
2759
+ auto &DAG = DCI.DAG ;
2760
+ SDLoc DL (N);
2761
+ SDValue Src = N->getOperand (0 );
2762
+ EVT VT = N->getValueType (0 );
2763
+ EVT SrcVT = Src.getValueType ();
2764
+
2765
+ // bitcast <N x i1> to iN
2766
+ // ==> bitmask
2767
+ if (DCI.isBeforeLegalize () && VT.isScalarInteger () &&
2768
+ SrcVT.isFixedLengthVector () && SrcVT.getScalarType () == MVT::i1) {
2769
+ unsigned NumElts = SrcVT.getVectorNumElements ();
2770
+ assert (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16 );
2771
+ EVT Width = MVT::getIntegerVT (128 / NumElts);
2772
+ return DAG.getZExtOrTrunc (
2773
+ DAG.getNode (ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
2774
+ {DAG.getConstant (Intrinsic::wasm_bitmask, DL, MVT::i32),
2775
+ DAG.getSExtOrTrunc (N->getOperand (0 ), DL,
2776
+ SrcVT.changeVectorElementType (Width))}),
2777
+ DL, VT);
2778
+ }
2779
+
2780
+ return SDValue ();
2781
+ }
2782
+
2783
+ static SDValue performSETCCCombine (SDNode *N,
2784
+ TargetLowering::DAGCombinerInfo &DCI) {
2785
+ auto &DAG = DCI.DAG ;
2786
+
2787
+ SDValue LHS = N->getOperand (0 );
2788
+ SDValue RHS = N->getOperand (1 );
2789
+ ISD::CondCode Cond = cast<CondCodeSDNode>(N->getOperand (2 ))->get ();
2790
+ SDLoc DL (N);
2791
+ EVT VT = N->getValueType (0 );
2792
+
2793
+ // setcc (iN (bitcast (vNi1 X))), 0, ne
2794
+ // ==> any_true (vNi1 X)
2795
+ // setcc (iN (bitcast (vNi1 X))), 0, eq
2796
+ // ==> xor (any_true (vNi1 X)), -1
2797
+ // setcc (iN (bitcast (vNi1 X))), -1, eq
2798
+ // ==> all_true (vNi1 X)
2799
+ // setcc (iN (bitcast (vNi1 X))), -1, ne
2800
+ // ==> xor (all_true (vNi1 X)), -1
2801
+ if (DCI.isBeforeLegalize () && VT.isScalarInteger () &&
2802
+ (Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
2803
+ (isNullConstant (RHS) || isAllOnesConstant (RHS)) &&
2804
+ LHS->getOpcode () == ISD::BITCAST) {
2805
+ EVT FromVT = LHS->getOperand (0 ).getValueType ();
2806
+ if (FromVT.isFixedLengthVector () &&
2807
+ FromVT.getVectorElementType () == MVT::i1) {
2808
+ int Intrin = isNullConstant (RHS) ? Intrinsic::wasm_anytrue
2809
+ : Intrinsic::wasm_alltrue;
2810
+ unsigned NumElts = FromVT.getVectorNumElements ();
2811
+ assert (NumElts == 2 || NumElts == 4 || NumElts == 8 || NumElts == 16 );
2812
+ EVT Width = MVT::getIntegerVT (128 / NumElts);
2813
+ SDValue Ret = DAG.getZExtOrTrunc (
2814
+ DAG.getNode (
2815
+ ISD::INTRINSIC_WO_CHAIN, DL, MVT::i32,
2816
+ {DAG.getConstant (Intrin, DL, MVT::i32),
2817
+ DAG.getSExtOrTrunc (LHS->getOperand (0 ), DL,
2818
+ FromVT.changeVectorElementType (Width))}),
2819
+ DL, MVT::i1);
2820
+ if ((isNullConstant (RHS) && (Cond == ISD::SETEQ)) ||
2821
+ (isAllOnesConstant (RHS) && (Cond == ISD::SETNE))) {
2822
+ Ret = DAG.getNOT (DL, Ret, MVT::i1);
2823
+ }
2824
+ return DAG.getZExtOrTrunc (Ret, DL, VT);
2825
+ }
2826
+ }
2827
+
2828
+ return SDValue ();
2829
+ }
2830
+
2695
2831
SDValue
2696
2832
WebAssemblyTargetLowering::PerformDAGCombine (SDNode *N,
2697
2833
DAGCombinerInfo &DCI) const {
2698
2834
switch (N->getOpcode ()) {
2699
2835
default :
2700
2836
return SDValue ();
2837
+ case ISD::BITCAST:
2838
+ return performBitcastCombine (N, DCI);
2839
+ case ISD::SETCC:
2840
+ return performSETCCCombine (N, DCI);
2701
2841
case ISD::VECTOR_SHUFFLE:
2702
2842
return performVECTOR_SHUFFLECombine (N, DCI);
2703
2843
case ISD::SIGN_EXTEND:
0 commit comments