From dc72ec808d97a83fe9d3c1889302067cbee24c91 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 18 Dec 2024 19:19:14 -0800 Subject: [PATCH 001/209] [RISCV] Custom legalize vp.merge for mask vectors. (#120479) The default legalization uses vmslt with a vector of XLen to compute a mask. This doesn't work if the type isn't legal. For fixed vectors it will scalarize. For scalable vectors it crashes the compiler. This patch uses an alternate strategy that promotes the i1 vector to an i8 vector and does the merge. I don't claim this to be the best lowering. I wrote it quickly almost 3 years ago when a crash was reported in our downstream. Fixes #120405. --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 72 +++++- llvm/lib/Target/RISCV/RISCVISelLowering.h | 1 + .../RISCV/rvv/fixed-vectors-vpmerge.ll | 184 ++++++++++++++- llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll | 211 +++++++++++++++++- 4 files changed, 454 insertions(+), 14 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b703eb90e8ef3..affc29ec18ff7 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -758,9 +758,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, Custom); setOperationAction(ISD::SELECT, VT, Custom); - setOperationAction( - {ISD::SELECT_CC, ISD::VSELECT, ISD::VP_MERGE, ISD::VP_SELECT}, VT, - Expand); + setOperationAction({ISD::SELECT_CC, ISD::VSELECT, ISD::VP_SELECT}, VT, + Expand); + setOperationAction(ISD::VP_MERGE, VT, Custom); setOperationAction({ISD::VP_CTTZ_ELTS, ISD::VP_CTTZ_ELTS_ZERO_UNDEF}, VT, Custom); @@ -1237,6 +1237,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, ISD::VP_SETCC, ISD::VP_TRUNCATE}, VT, Custom); + setOperationAction(ISD::VP_MERGE, VT, Custom); + setOperationAction(ISD::EXPERIMENTAL_VP_SPLICE, VT, Custom); setOperationAction(ISD::EXPERIMENTAL_VP_REVERSE, VT, Custom); continue; @@ -7492,8 +7494,11 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerSET_ROUNDING(Op, DAG); case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG); - case ISD::VP_SELECT: case ISD::VP_MERGE: + if (Op.getSimpleValueType().getVectorElementType() == MVT::i1) + return lowerVPMergeMask(Op, DAG); + [[fallthrough]]; + case ISD::VP_SELECT: case ISD::VP_ADD: case ISD::VP_SUB: case ISD::VP_MUL: @@ -12078,6 +12083,65 @@ SDValue RISCVTargetLowering::lowerVPFPIntConvOp(SDValue Op, return convertFromScalableVector(VT, Result, DAG, Subtarget); } +SDValue RISCVTargetLowering::lowerVPMergeMask(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + MVT VT = Op.getSimpleValueType(); + MVT XLenVT = Subtarget.getXLenVT(); + + SDValue Mask = Op.getOperand(0); + SDValue TrueVal = Op.getOperand(1); + SDValue FalseVal = Op.getOperand(2); + SDValue VL = Op.getOperand(3); + + // Use default legalization if a vector of EVL type would be legal. + EVT EVLVecVT = EVT::getVectorVT(*DAG.getContext(), VL.getValueType(), + VT.getVectorElementCount()); + if (isTypeLegal(EVLVecVT)) + return SDValue(); + + MVT ContainerVT = VT; + if (VT.isFixedLengthVector()) { + ContainerVT = getContainerForFixedLengthVector(VT); + Mask = convertToScalableVector(ContainerVT, Mask, DAG, Subtarget); + TrueVal = convertToScalableVector(ContainerVT, TrueVal, DAG, Subtarget); + FalseVal = convertToScalableVector(ContainerVT, FalseVal, DAG, Subtarget); + } + + // Promote to a vector of i8. + MVT PromotedVT = ContainerVT.changeVectorElementType(MVT::i8); + + // Promote TrueVal and FalseVal using VLMax. + // FIXME: Is there a better way to do this? + SDValue VLMax = DAG.getRegister(RISCV::X0, XLenVT); + SDValue SplatOne = DAG.getNode(RISCVISD::VMV_V_X_VL, DL, PromotedVT, + DAG.getUNDEF(PromotedVT), + DAG.getConstant(1, DL, XLenVT), VLMax); + SDValue SplatZero = DAG.getNode(RISCVISD::VMV_V_X_VL, DL, PromotedVT, + DAG.getUNDEF(PromotedVT), + DAG.getConstant(0, DL, XLenVT), VLMax); + TrueVal = DAG.getNode(RISCVISD::VMERGE_VL, DL, PromotedVT, TrueVal, SplatOne, + SplatZero, DAG.getUNDEF(PromotedVT), VL); + // Any element past VL uses FalseVal, so use VLMax + FalseVal = DAG.getNode(RISCVISD::VMERGE_VL, DL, PromotedVT, FalseVal, + SplatOne, SplatZero, DAG.getUNDEF(PromotedVT), VLMax); + + // VP_MERGE the two promoted values. + SDValue VPMerge = DAG.getNode(RISCVISD::VMERGE_VL, DL, PromotedVT, Mask, + TrueVal, FalseVal, FalseVal, VL); + + // Convert back to mask. + SDValue TrueMask = DAG.getNode(RISCVISD::VMSET_VL, DL, ContainerVT, VL); + SDValue Result = DAG.getNode( + RISCVISD::SETCC_VL, DL, ContainerVT, + {VPMerge, DAG.getConstant(0, DL, PromotedVT), DAG.getCondCode(ISD::SETNE), + DAG.getUNDEF(getMaskTypeFor(ContainerVT)), TrueMask, VLMax}); + + if (VT.isFixedLengthVector()) + Result = convertFromScalableVector(VT, Result, DAG, Subtarget); + return Result; +} + SDValue RISCVTargetLowering::lowerVPSpliceExperimental(SDValue Op, SelectionDAG &DAG) const { diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 0944bb8793a94..4c78fd784a3c8 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -996,6 +996,7 @@ class RISCVTargetLowering : public TargetLowering { SDValue lowerLogicVPOp(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVPExtMaskOp(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVPSetCCMaskOp(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVPMergeMask(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVPSplatExperimental(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVPSpliceExperimental(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVPReverseExperimental(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpmerge.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpmerge.ll index a53d33e6120d5..6394542479d1b 100644 --- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpmerge.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vpmerge.ll @@ -58,6 +58,182 @@ define <4 x i1> @vpmerge_vv_v4i1(<4 x i1> %va, <4 x i1> %vb, <4 x i1> %m, i32 ze ret <4 x i1> %v } +define <8 x i1> @vpmerge_vv_v8i1(<8 x i1> %va, <8 x i1> %vb, <8 x i1> %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_vv_v8i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; RV32-NEXT: vid.v v10 +; RV32-NEXT: vmsltu.vx v12, v10, a0 +; RV32-NEXT: vmand.mm v9, v9, v12 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_vv_v8i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetivli zero, 8, e64, m4, ta, ma +; RV64-NEXT: vid.v v12 +; RV64-NEXT: vmsltu.vx v10, v12, a0 +; RV64-NEXT: vmand.mm v9, v9, v10 +; RV64-NEXT: vmandn.mm v8, v8, v9 +; RV64-NEXT: vmand.mm v9, v0, v9 +; RV64-NEXT: vmor.mm v0, v9, v8 +; RV64-NEXT: ret +; +; RV32ZVFHMIN-LABEL: vpmerge_vv_v8i1: +; RV32ZVFHMIN: # %bb.0: +; RV32ZVFHMIN-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; RV32ZVFHMIN-NEXT: vid.v v10 +; RV32ZVFHMIN-NEXT: vmsltu.vx v12, v10, a0 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v9, v12 +; RV32ZVFHMIN-NEXT: vmandn.mm v8, v8, v9 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v0, v9 +; RV32ZVFHMIN-NEXT: vmor.mm v0, v9, v8 +; RV32ZVFHMIN-NEXT: ret +; +; RV64ZVFHMIN-LABEL: vpmerge_vv_v8i1: +; RV64ZVFHMIN: # %bb.0: +; RV64ZVFHMIN-NEXT: vsetivli zero, 8, e64, m4, ta, ma +; RV64ZVFHMIN-NEXT: vid.v v12 +; RV64ZVFHMIN-NEXT: vmsltu.vx v10, v12, a0 +; RV64ZVFHMIN-NEXT: vmand.mm v9, v9, v10 +; RV64ZVFHMIN-NEXT: vmandn.mm v8, v8, v9 +; RV64ZVFHMIN-NEXT: vmand.mm v9, v0, v9 +; RV64ZVFHMIN-NEXT: vmor.mm v0, v9, v8 +; RV64ZVFHMIN-NEXT: ret + %v = call <8 x i1> @llvm.vp.merge.v8i1(<8 x i1> %m, <8 x i1> %va, <8 x i1> %vb, i32 %evl) + ret <8 x i1> %v +} + +define <16 x i1> @vpmerge_vv_v16i1(<16 x i1> %va, <16 x i1> %vb, <16 x i1> %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_vv_v16i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetivli zero, 16, e32, m4, ta, ma +; RV32-NEXT: vid.v v12 +; RV32-NEXT: vmsltu.vx v10, v12, a0 +; RV32-NEXT: vmand.mm v9, v9, v10 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_vv_v16i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetivli zero, 16, e64, m8, ta, ma +; RV64-NEXT: vid.v v16 +; RV64-NEXT: vmsltu.vx v10, v16, a0 +; RV64-NEXT: vmand.mm v9, v9, v10 +; RV64-NEXT: vmandn.mm v8, v8, v9 +; RV64-NEXT: vmand.mm v9, v0, v9 +; RV64-NEXT: vmor.mm v0, v9, v8 +; RV64-NEXT: ret +; +; RV32ZVFHMIN-LABEL: vpmerge_vv_v16i1: +; RV32ZVFHMIN: # %bb.0: +; RV32ZVFHMIN-NEXT: vsetivli zero, 16, e32, m4, ta, ma +; RV32ZVFHMIN-NEXT: vid.v v12 +; RV32ZVFHMIN-NEXT: vmsltu.vx v10, v12, a0 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v9, v10 +; RV32ZVFHMIN-NEXT: vmandn.mm v8, v8, v9 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v0, v9 +; RV32ZVFHMIN-NEXT: vmor.mm v0, v9, v8 +; RV32ZVFHMIN-NEXT: ret +; +; RV64ZVFHMIN-LABEL: vpmerge_vv_v16i1: +; RV64ZVFHMIN: # %bb.0: +; RV64ZVFHMIN-NEXT: vsetivli zero, 16, e64, m8, ta, ma +; RV64ZVFHMIN-NEXT: vid.v v16 +; RV64ZVFHMIN-NEXT: vmsltu.vx v10, v16, a0 +; RV64ZVFHMIN-NEXT: vmand.mm v9, v9, v10 +; RV64ZVFHMIN-NEXT: vmandn.mm v8, v8, v9 +; RV64ZVFHMIN-NEXT: vmand.mm v9, v0, v9 +; RV64ZVFHMIN-NEXT: vmor.mm v0, v9, v8 +; RV64ZVFHMIN-NEXT: ret + %v = call <16 x i1> @llvm.vp.merge.v16i1(<16 x i1> %m, <16 x i1> %va, <16 x i1> %vb, i32 %evl) + ret <16 x i1> %v +} + +define <32 x i1> @vpmerge_vv_v32i1(<32 x i1> %va, <32 x i1> %vb, <32 x i1> %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_vv_v32i1: +; RV32: # %bb.0: +; RV32-NEXT: li a1, 32 +; RV32-NEXT: vsetvli zero, a1, e32, m8, ta, ma +; RV32-NEXT: vid.v v16 +; RV32-NEXT: vmsltu.vx v10, v16, a0 +; RV32-NEXT: vmand.mm v9, v9, v10 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_vv_v32i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64-NEXT: vmv.v.i v10, 0 +; RV64-NEXT: vsetvli zero, a0, e8, m2, ta, ma +; RV64-NEXT: vmerge.vim v12, v10, 1, v0 +; RV64-NEXT: vmv1r.v v0, v8 +; RV64-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64-NEXT: vmerge.vim v10, v10, 1, v0 +; RV64-NEXT: vmv1r.v v0, v9 +; RV64-NEXT: vsetvli zero, a0, e8, m2, tu, ma +; RV64-NEXT: vmerge.vvm v10, v10, v12, v0 +; RV64-NEXT: vsetvli a0, zero, e8, m2, ta, ma +; RV64-NEXT: vmsne.vi v0, v10, 0 +; RV64-NEXT: ret +; +; RV32ZVFHMIN-LABEL: vpmerge_vv_v32i1: +; RV32ZVFHMIN: # %bb.0: +; RV32ZVFHMIN-NEXT: li a1, 32 +; RV32ZVFHMIN-NEXT: vsetvli zero, a1, e32, m8, ta, ma +; RV32ZVFHMIN-NEXT: vid.v v16 +; RV32ZVFHMIN-NEXT: vmsltu.vx v10, v16, a0 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v9, v10 +; RV32ZVFHMIN-NEXT: vmandn.mm v8, v8, v9 +; RV32ZVFHMIN-NEXT: vmand.mm v9, v0, v9 +; RV32ZVFHMIN-NEXT: vmor.mm v0, v9, v8 +; RV32ZVFHMIN-NEXT: ret +; +; RV64ZVFHMIN-LABEL: vpmerge_vv_v32i1: +; RV64ZVFHMIN: # %bb.0: +; RV64ZVFHMIN-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64ZVFHMIN-NEXT: vmv.v.i v10, 0 +; RV64ZVFHMIN-NEXT: vsetvli zero, a0, e8, m2, ta, ma +; RV64ZVFHMIN-NEXT: vmerge.vim v12, v10, 1, v0 +; RV64ZVFHMIN-NEXT: vmv1r.v v0, v8 +; RV64ZVFHMIN-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64ZVFHMIN-NEXT: vmerge.vim v10, v10, 1, v0 +; RV64ZVFHMIN-NEXT: vmv1r.v v0, v9 +; RV64ZVFHMIN-NEXT: vsetvli zero, a0, e8, m2, tu, ma +; RV64ZVFHMIN-NEXT: vmerge.vvm v10, v10, v12, v0 +; RV64ZVFHMIN-NEXT: vsetvli a0, zero, e8, m2, ta, ma +; RV64ZVFHMIN-NEXT: vmsne.vi v0, v10, 0 +; RV64ZVFHMIN-NEXT: ret + %v = call <32 x i1> @llvm.vp.merge.v32i1(<32 x i1> %m, <32 x i1> %va, <32 x i1> %vb, i32 %evl) + ret <32 x i1> %v +} + +define <64 x i1> @vpmerge_vv_v64i1(<64 x i1> %va, <64 x i1> %vb, <64 x i1> %m, i32 zeroext %evl) { +; CHECK-LABEL: vpmerge_vv_v64i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a1, zero, e8, m4, ta, ma +; CHECK-NEXT: vmv.v.i v12, 0 +; CHECK-NEXT: vsetvli zero, a0, e8, m4, ta, ma +; CHECK-NEXT: vmerge.vim v16, v12, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v8 +; CHECK-NEXT: vsetvli a1, zero, e8, m4, ta, ma +; CHECK-NEXT: vmerge.vim v12, v12, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vsetvli zero, a0, e8, m4, tu, ma +; CHECK-NEXT: vmerge.vvm v12, v12, v16, v0 +; CHECK-NEXT: vsetvli a0, zero, e8, m4, ta, ma +; CHECK-NEXT: vmsne.vi v0, v12, 0 +; CHECK-NEXT: ret + %v = call <64 x i1> @llvm.vp.merge.v64i1(<64 x i1> %m, <64 x i1> %va, <64 x i1> %vb, i32 %evl) + ret <64 x i1> %v +} + declare <2 x i8> @llvm.vp.merge.v2i8(<2 x i1>, <2 x i8>, <2 x i8>, i32) define <2 x i8> @vpmerge_vv_v2i8(<2 x i8> %va, <2 x i8> %vb, <2 x i1> %m, i32 zeroext %evl) { @@ -1188,10 +1364,10 @@ define <32 x double> @vpmerge_vv_v32f64(<32 x double> %va, <32 x double> %vb, <3 ; CHECK-NEXT: vle64.v v8, (a0) ; CHECK-NEXT: li a1, 16 ; CHECK-NEXT: mv a0, a2 -; CHECK-NEXT: bltu a2, a1, .LBB79_2 +; CHECK-NEXT: bltu a2, a1, .LBB83_2 ; CHECK-NEXT: # %bb.1: ; CHECK-NEXT: li a0, 16 -; CHECK-NEXT: .LBB79_2: +; CHECK-NEXT: .LBB83_2: ; CHECK-NEXT: vsetvli zero, a0, e64, m8, tu, ma ; CHECK-NEXT: vmerge.vvm v8, v8, v16, v0 ; CHECK-NEXT: addi a0, a2, -16 @@ -1221,10 +1397,10 @@ define <32 x double> @vpmerge_vf_v32f64(double %a, <32 x double> %vb, <32 x i1> ; CHECK: # %bb.0: ; CHECK-NEXT: li a2, 16 ; CHECK-NEXT: mv a1, a0 -; CHECK-NEXT: bltu a0, a2, .LBB80_2 +; CHECK-NEXT: bltu a0, a2, .LBB84_2 ; CHECK-NEXT: # %bb.1: ; CHECK-NEXT: li a1, 16 -; CHECK-NEXT: .LBB80_2: +; CHECK-NEXT: .LBB84_2: ; CHECK-NEXT: vsetvli zero, a1, e64, m8, tu, ma ; CHECK-NEXT: vfmerge.vfm v8, v8, fa0, v0 ; CHECK-NEXT: addi a1, a0, -16 diff --git a/llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll index 88a8ebcc90054..4cd77185e6930 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vpmerge-sdnode.ll @@ -35,6 +35,205 @@ define @vpmerge_nxv1i1( %va, %v } +define @vpmerge_nxv2i1( %va, %vb, %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_nxv2i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetvli a1, zero, e32, m1, ta, ma +; RV32-NEXT: vid.v v10 +; RV32-NEXT: vmsltu.vx v10, v10, a0 +; RV32-NEXT: vmand.mm v9, v9, v10 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_nxv2i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetvli a1, zero, e64, m2, ta, ma +; RV64-NEXT: vid.v v10 +; RV64-NEXT: vmsltu.vx v12, v10, a0 +; RV64-NEXT: vmand.mm v9, v9, v12 +; RV64-NEXT: vmandn.mm v8, v8, v9 +; RV64-NEXT: vmand.mm v9, v0, v9 +; RV64-NEXT: vmor.mm v0, v9, v8 +; RV64-NEXT: ret + %v = call @llvm.vp.merge.nxv2i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv4i1( %va, %vb, %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_nxv4i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetvli a1, zero, e32, m2, ta, ma +; RV32-NEXT: vid.v v10 +; RV32-NEXT: vmsltu.vx v12, v10, a0 +; RV32-NEXT: vmand.mm v9, v9, v12 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_nxv4i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetvli a1, zero, e64, m4, ta, ma +; RV64-NEXT: vid.v v12 +; RV64-NEXT: vmsltu.vx v10, v12, a0 +; RV64-NEXT: vmand.mm v9, v9, v10 +; RV64-NEXT: vmandn.mm v8, v8, v9 +; RV64-NEXT: vmand.mm v9, v0, v9 +; RV64-NEXT: vmor.mm v0, v9, v8 +; RV64-NEXT: ret + %v = call @llvm.vp.merge.nxv4i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv8i1( %va, %vb, %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_nxv8i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetvli a1, zero, e32, m4, ta, ma +; RV32-NEXT: vid.v v12 +; RV32-NEXT: vmsltu.vx v10, v12, a0 +; RV32-NEXT: vmand.mm v9, v9, v10 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_nxv8i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetvli a1, zero, e64, m8, ta, ma +; RV64-NEXT: vid.v v16 +; RV64-NEXT: vmsltu.vx v10, v16, a0 +; RV64-NEXT: vmand.mm v9, v9, v10 +; RV64-NEXT: vmandn.mm v8, v8, v9 +; RV64-NEXT: vmand.mm v9, v0, v9 +; RV64-NEXT: vmor.mm v0, v9, v8 +; RV64-NEXT: ret + %v = call @llvm.vp.merge.nxv8i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv16i1( %va, %vb, %m, i32 zeroext %evl) { +; RV32-LABEL: vpmerge_nxv16i1: +; RV32: # %bb.0: +; RV32-NEXT: vsetvli a1, zero, e32, m8, ta, ma +; RV32-NEXT: vid.v v16 +; RV32-NEXT: vmsltu.vx v10, v16, a0 +; RV32-NEXT: vmand.mm v9, v9, v10 +; RV32-NEXT: vmandn.mm v8, v8, v9 +; RV32-NEXT: vmand.mm v9, v0, v9 +; RV32-NEXT: vmor.mm v0, v9, v8 +; RV32-NEXT: ret +; +; RV64-LABEL: vpmerge_nxv16i1: +; RV64: # %bb.0: +; RV64-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64-NEXT: vmv.v.i v10, 0 +; RV64-NEXT: vsetvli zero, a0, e8, m2, ta, ma +; RV64-NEXT: vmerge.vim v12, v10, 1, v0 +; RV64-NEXT: vmv1r.v v0, v8 +; RV64-NEXT: vsetvli a1, zero, e8, m2, ta, ma +; RV64-NEXT: vmerge.vim v10, v10, 1, v0 +; RV64-NEXT: vmv1r.v v0, v9 +; RV64-NEXT: vsetvli zero, a0, e8, m2, tu, ma +; RV64-NEXT: vmerge.vvm v10, v10, v12, v0 +; RV64-NEXT: vsetvli a0, zero, e8, m2, ta, ma +; RV64-NEXT: vmsne.vi v0, v10, 0 +; RV64-NEXT: ret + %v = call @llvm.vp.merge.nxv16i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv32i1( %va, %vb, %m, i32 zeroext %evl) { +; CHECK-LABEL: vpmerge_nxv32i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a1, zero, e8, m4, ta, ma +; CHECK-NEXT: vmv.v.i v12, 0 +; CHECK-NEXT: vsetvli zero, a0, e8, m4, ta, ma +; CHECK-NEXT: vmerge.vim v16, v12, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v8 +; CHECK-NEXT: vsetvli a1, zero, e8, m4, ta, ma +; CHECK-NEXT: vmerge.vim v12, v12, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vsetvli zero, a0, e8, m4, tu, ma +; CHECK-NEXT: vmerge.vvm v12, v12, v16, v0 +; CHECK-NEXT: vsetvli a0, zero, e8, m4, ta, ma +; CHECK-NEXT: vmsne.vi v0, v12, 0 +; CHECK-NEXT: ret + %v = call @llvm.vp.merge.nxv32i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv64i1( %va, %vb, %m, i32 zeroext %evl) { +; CHECK-LABEL: vpmerge_nxv64i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a1, zero, e8, m8, ta, ma +; CHECK-NEXT: vmv.v.i v16, 0 +; CHECK-NEXT: vsetvli zero, a0, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v24, v16, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v8 +; CHECK-NEXT: vsetvli a1, zero, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v16, v16, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vsetvli zero, a0, e8, m8, tu, ma +; CHECK-NEXT: vmerge.vvm v16, v16, v24, v0 +; CHECK-NEXT: vsetvli a0, zero, e8, m8, ta, ma +; CHECK-NEXT: vmsne.vi v0, v16, 0 +; CHECK-NEXT: ret + %v = call @llvm.vp.merge.nxv64i1( %m, %va, %vb, i32 %evl) + ret %v +} + +define @vpmerge_nxv128i1( %va, %vb, %m, i32 zeroext %evl) { +; CHECK-LABEL: vpmerge_nxv128i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 1, e8, m1, ta, ma +; CHECK-NEXT: vmv1r.v v7, v12 +; CHECK-NEXT: vmv1r.v v4, v11 +; CHECK-NEXT: vmv1r.v v6, v10 +; CHECK-NEXT: vmv1r.v v3, v9 +; CHECK-NEXT: vmv1r.v v5, v8 +; CHECK-NEXT: csrr a2, vlenb +; CHECK-NEXT: slli a2, a2, 3 +; CHECK-NEXT: mv a1, a0 +; CHECK-NEXT: bltu a0, a2, .LBB7_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: mv a1, a2 +; CHECK-NEXT: .LBB7_2: +; CHECK-NEXT: vsetvli a3, zero, e8, m8, ta, ma +; CHECK-NEXT: vmv.v.i v16, 0 +; CHECK-NEXT: sub a2, a0, a2 +; CHECK-NEXT: vsetvli zero, a1, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v24, v16, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v3 +; CHECK-NEXT: vsetvli a3, zero, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v16, v16, 1, v0 +; CHECK-NEXT: sltu a0, a0, a2 +; CHECK-NEXT: vmv1r.v v0, v4 +; CHECK-NEXT: vsetvli zero, a1, e8, m8, tu, ma +; CHECK-NEXT: vmerge.vvm v16, v16, v24, v0 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: vsetvli a1, zero, e8, m8, ta, ma +; CHECK-NEXT: vmsne.vi v9, v16, 0 +; CHECK-NEXT: and a0, a0, a2 +; CHECK-NEXT: vmv1r.v v0, v5 +; CHECK-NEXT: vmv.v.i v24, 0 +; CHECK-NEXT: vsetvli zero, a0, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v16, v24, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v6 +; CHECK-NEXT: vsetvli a1, zero, e8, m8, ta, ma +; CHECK-NEXT: vmerge.vim v24, v24, 1, v0 +; CHECK-NEXT: vmv1r.v v0, v7 +; CHECK-NEXT: vsetvli zero, a0, e8, m8, tu, ma +; CHECK-NEXT: vmerge.vvm v24, v24, v16, v0 +; CHECK-NEXT: vsetvli a0, zero, e8, m8, ta, ma +; CHECK-NEXT: vmsne.vi v8, v24, 0 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: ret + %v = call @llvm.vp.merge.nxv128i1( %m, %va, %vb, i32 %evl) + ret %v +} + declare @llvm.vp.merge.nxv1i8(, , , i32) define @vpmerge_vv_nxv1i8( %va, %vb, %m, i32 zeroext %evl) { @@ -378,10 +577,10 @@ define @vpmerge_vv_nxv128i8( %va, @vpmerge_vx_nxv128i8(i8 %a, %vb, ; CHECK-NEXT: and a3, a4, a3 ; CHECK-NEXT: vsetvli zero, a3, e8, m8, tu, ma ; CHECK-NEXT: vmerge.vxm v16, v16, a0, v0 -; CHECK-NEXT: bltu a2, a1, .LBB29_2 +; CHECK-NEXT: bltu a2, a1, .LBB36_2 ; CHECK-NEXT: # %bb.1: ; CHECK-NEXT: mv a2, a1 -; CHECK-NEXT: .LBB29_2: +; CHECK-NEXT: .LBB36_2: ; CHECK-NEXT: vmv1r.v v0, v24 ; CHECK-NEXT: vsetvli zero, a2, e8, m8, tu, ma ; CHECK-NEXT: vmerge.vxm v8, v8, a0, v0 @@ -440,10 +639,10 @@ define @vpmerge_vi_nxv128i8( %vb, Date: Wed, 18 Dec 2024 20:23:50 -0700 Subject: [PATCH 002/209] [Sema] Fix tautological bounds check warning with -fwrapv (#120480) The tautological bounds check warning added in #120222 does not take into account whether signed integer overflow is well defined or not, which could result in a developer removing a bounds check that may not actually be always false because of different overflow semantics. ```c int check(const int* foo, unsigned int idx) { return foo + idx < foo; } ``` ``` $ clang -O2 -c test.c test.c:3:19: warning: pointer comparison always evaluates to false [-Wtautological-compare] 3 | return foo + idx < foo; | ^ 1 warning generated. # Bounds check is eliminated without -fwrapv, warning was correct $ llvm-objdump -dr test.o ... 0000000000000000 : 0: 31 c0 xorl %eax, %eax 2: c3 retq ``` ``` $ clang -O2 -fwrapv -c test.c test.c:3:19: warning: pointer comparison always evaluates to false [-Wtautological-compare] 3 | return foo + idx < foo; | ^ 1 warning generated. # Bounds check remains, warning was wrong $ llvm-objdump -dr test.o 0000000000000000 : 0: 89 f0 movl %esi, %eax 2: 48 8d 0c 87 leaq (%rdi,%rax,4), %rcx 6: 31 c0 xorl %eax, %eax 8: 48 39 f9 cmpq %rdi, %rcx b: 0f 92 c0 setb %al e: c3 retq ``` --- clang/lib/Sema/SemaExpr.cpp | 7 ++++--- clang/test/Sema/tautological-pointer-comparison.c | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e06a092177ef0..24f7d27c69115 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11789,10 +11789,11 @@ static bool checkForArray(const Expr *E) { /// Detect patterns ptr + size >= ptr and ptr + size < ptr, where ptr is a /// pointer and size is an unsigned integer. Return whether the result is /// always true/false. -static std::optional isTautologicalBoundsCheck(const Expr *LHS, +static std::optional isTautologicalBoundsCheck(Sema &S, const Expr *LHS, const Expr *RHS, BinaryOperatorKind Opc) { - if (!LHS->getType()->isPointerType()) + if (!LHS->getType()->isPointerType() || + S.getLangOpts().isSignedOverflowDefined()) return std::nullopt; // Canonicalize to >= or < predicate. @@ -11940,7 +11941,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, << 1 /*array comparison*/ << Result); } else if (std::optional Res = - isTautologicalBoundsCheck(LHS, RHS, Opc)) { + isTautologicalBoundsCheck(S, LHS, RHS, Opc)) { S.DiagRuntimeBehavior(Loc, nullptr, S.PDiag(diag::warn_comparison_always) << 2 /*pointer comparison*/ diff --git a/clang/test/Sema/tautological-pointer-comparison.c b/clang/test/Sema/tautological-pointer-comparison.c index 19cd20e5f7d21..1c5973b01a30d 100644 --- a/clang/test/Sema/tautological-pointer-comparison.c +++ b/clang/test/Sema/tautological-pointer-comparison.c @@ -1,4 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fwrapv -verify=fwrapv %s + +// fwrapv-no-diagnostics int add_ptr_idx_ult_ptr(const char *ptr, unsigned index) { return ptr + index < ptr; // expected-warning {{pointer comparison always evaluates to false}} From 1cc926b8b6976ac4a5a411eae564cfde2df1ef9d Mon Sep 17 00:00:00 2001 From: Pavel Samolysov Date: Thu, 19 Dec 2024 06:36:48 +0300 Subject: [PATCH 003/209] [ADT] Add a unittest for the ScopedHashTable class (#120183) The ScopedHashTable class is particularly used to develop string tables for parsers and code convertors. For instance, the MLIRGen class from the toy example for MLIR actively uses this class to define scopes for declared variables. To demonstrate common use cases for the ScopedHashTable class as well as to check its behavior in different situations, the unittest has been added. Signed-off-by: Pavel Samolysov --- llvm/unittests/ADT/CMakeLists.txt | 1 + llvm/unittests/ADT/ScopedHashTableTest.cpp | 145 +++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 llvm/unittests/ADT/ScopedHashTableTest.cpp diff --git a/llvm/unittests/ADT/CMakeLists.txt b/llvm/unittests/ADT/CMakeLists.txt index 07568ad0c64e3..dafd73518aedb 100644 --- a/llvm/unittests/ADT/CMakeLists.txt +++ b/llvm/unittests/ADT/CMakeLists.txt @@ -67,6 +67,7 @@ add_llvm_unittest(ADTTests SCCIteratorTest.cpp STLExtrasTest.cpp STLForwardCompatTest.cpp + ScopedHashTableTest.cpp ScopeExitTest.cpp SequenceTest.cpp SetOperationsTest.cpp diff --git a/llvm/unittests/ADT/ScopedHashTableTest.cpp b/llvm/unittests/ADT/ScopedHashTableTest.cpp new file mode 100644 index 0000000000000..64afa948d9a17 --- /dev/null +++ b/llvm/unittests/ADT/ScopedHashTableTest.cpp @@ -0,0 +1,145 @@ +//===- ScopedHashTableTest.cpp - ScopedHashTable unit tests ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ScopedHashTable.h" +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" +#include +#include + +using ::llvm::ScopedHashTable; +using ::llvm::ScopedHashTableScope; +using ::llvm::StringLiteral; +using ::llvm::StringRef; + +using ::testing::Test; + +class ScopedHashTableTest : public Test { +protected: + ScopedHashTableTest() { symbolTable.insert(kGlobalName, kGlobalValue); } + + ScopedHashTable symbolTable{}; + ScopedHashTableScope globalScope{symbolTable}; + + static constexpr StringLiteral kGlobalName = "global"; + static constexpr StringLiteral kGlobalValue = "gvalue"; + static constexpr StringLiteral kLocalName = "local"; + static constexpr StringLiteral kLocalValue = "lvalue"; + static constexpr StringLiteral kLocalValue2 = "lvalue2"; +}; + +TEST_F(ScopedHashTableTest, AccessWithNoActiveScope) { + EXPECT_EQ(symbolTable.count(kGlobalName), 1U); +} + +TEST_F(ScopedHashTableTest, AccessWithAScope) { + [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + EXPECT_EQ(symbolTable.count(kGlobalName), 1U); +} + +TEST_F(ScopedHashTableTest, InsertInScope) { + [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + symbolTable.insert(kLocalName, kLocalValue); + EXPECT_EQ(symbolTable.count(kLocalName), 1U); +} + +TEST_F(ScopedHashTableTest, InsertInLinearSortedScope) { + [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope2(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope3(symbolTable); + symbolTable.insert(kLocalName, kLocalValue); + EXPECT_EQ(symbolTable.count(kLocalName), 1U); +} + +TEST_F(ScopedHashTableTest, InsertInOutedScope) { + { + [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + symbolTable.insert(kLocalName, kLocalValue); + } + EXPECT_EQ(symbolTable.count(kLocalName), 0U); +} + +TEST_F(ScopedHashTableTest, OverrideInScope) { + [[maybe_unused]] ScopedHashTableScope funScope(symbolTable); + symbolTable.insert(kLocalName, kLocalValue); + { + [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + symbolTable.insert(kLocalName, kLocalValue2); + EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue2); + } + EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue); +} + +TEST_F(ScopedHashTableTest, GetCurScope) { + EXPECT_EQ(symbolTable.getCurScope(), &globalScope); + { + ScopedHashTableScope funScope(symbolTable); + ScopedHashTableScope funScope2(symbolTable); + EXPECT_EQ(symbolTable.getCurScope(), &funScope2); + { + ScopedHashTableScope blockScope(symbolTable); + EXPECT_EQ(symbolTable.getCurScope(), &blockScope); + } + EXPECT_EQ(symbolTable.getCurScope(), &funScope2); + } + EXPECT_EQ(symbolTable.getCurScope(), &globalScope); +} + +TEST_F(ScopedHashTableTest, PopScope) { + using SymbolTableScopeTy = ScopedHashTable::ScopeTy; + + std::stack ExpectedValues; + std::stack> Scopes; + + Scopes.emplace(std::make_unique(symbolTable)); + ExpectedValues.emplace(kLocalValue); + symbolTable.insert(kGlobalName, kLocalValue); + + Scopes.emplace(std::make_unique(symbolTable)); + ExpectedValues.emplace(kLocalValue2); + symbolTable.insert(kGlobalName, kLocalValue2); + + while (symbolTable.getCurScope() != &globalScope) { + EXPECT_EQ(symbolTable.getCurScope(), Scopes.top().get()); + EXPECT_EQ(symbolTable.lookup(kGlobalName), ExpectedValues.top()); + ExpectedValues.pop(); + Scopes.pop(); // destructs the SymbolTableScopeTy instance implicitly + // calling Scopes.top()->~SymbolTableScopeTy(); + EXPECT_NE(symbolTable.getCurScope(), nullptr); + } + ASSERT_TRUE(ExpectedValues.empty()); + ASSERT_TRUE(Scopes.empty()); + EXPECT_EQ(symbolTable.lookup(kGlobalName), kGlobalValue); +} + +TEST_F(ScopedHashTableTest, DISABLED_PopScopeOnStack) { + using SymbolTableScopeTy = ScopedHashTable::ScopeTy; + SymbolTableScopeTy funScope(symbolTable); + symbolTable.insert(kGlobalName, kLocalValue); + SymbolTableScopeTy funScope2(symbolTable); + symbolTable.insert(kGlobalName, kLocalValue2); + + std::stack expectedValues{{kLocalValue, kLocalValue2}}; + std::stack expectedScopes{{&funScope, &funScope2}}; + + while (symbolTable.getCurScope() != &globalScope) { + EXPECT_EQ(symbolTable.getCurScope(), expectedScopes.top()); + expectedScopes.pop(); + EXPECT_EQ(symbolTable.lookup(kGlobalName), expectedValues.top()); + expectedValues.pop(); + symbolTable.getCurScope()->~SymbolTableScopeTy(); + EXPECT_NE(symbolTable.getCurScope(), nullptr); + } + + // We have imbalanced scopes here: + // Assertion `HT.CurScope == this && "Scope imbalance!"' failed + // HT.CurScope is a pointer to the `globalScope` while + // `SymbolTableScopeTy.this` is still a pointer to `funScope2`. + // There is no way to write an assert on an assert in googletest so that we + // mark the test case as DISABLED. +} From 76275c0c41739a30939afd1709174861a587a823 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Thu, 19 Dec 2024 03:36:52 +0000 Subject: [PATCH 004/209] [gn build] Port 1cc926b8b697 --- llvm/utils/gn/secondary/llvm/unittests/ADT/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/llvm/unittests/ADT/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/ADT/BUILD.gn index 3541a7ae45291..92e596ea6a004 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/ADT/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/ADT/BUILD.gn @@ -76,6 +76,7 @@ unittest("ADTTests") { "STLExtrasTest.cpp", "STLForwardCompatTest.cpp", "ScopeExitTest.cpp", + "ScopedHashTableTest.cpp", "SequenceTest.cpp", "SetOperationsTest.cpp", "SetVectorTest.cpp", From fe2685303b215182b1acc5b6fb8be30c24bd6e8e Mon Sep 17 00:00:00 2001 From: Owen Pan Date: Wed, 18 Dec 2024 19:39:02 -0800 Subject: [PATCH 005/209] [clang-format] Fix a crash caused by commit f03bf8c45f43 --- clang/lib/Format/TokenAnnotator.cpp | 2 +- clang/unittests/Format/FormatTest.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 6a8caa23753f3..f2cfa7f49f62f 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -493,7 +493,7 @@ class AnnotatingParser { (CurrentToken->Next->is(tok::l_paren) || (CurrentToken->Next->is(tok::l_square) && (Line.MustBeDeclaration || - PrevNonComment->isTypeName(LangOpts))))) { + (PrevNonComment && PrevNonComment->isTypeName(LangOpts)))))) { OpeningParen.setType(OpeningParen.Next->is(tok::caret) ? TT_ObjCBlockLParen : TT_FunctionTypeLParen); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index e892f10433c55..47465a18e9a41 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -13691,6 +13691,10 @@ TEST_F(FormatTest, FormatsArrays) { " .aaaaaaaaaaaaaaaaaaaaaa();"); verifyFormat("a[::b::c];"); + verifyFormat("{\n" + " (*a)[0] = 1;\n" + "}"); + verifyNoCrash("a[,Y?)]", getLLVMStyleWithColumns(10)); FormatStyle NoColumnLimit = getLLVMStyleWithColumns(0); From c94ce0cca25229cd0e38560ad6e56a1a2f9a0c8b Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Wed, 18 Dec 2024 19:59:11 -0800 Subject: [PATCH 006/209] [ADT] Fix warnings This patch fixes warnings of the form: llvm/unittests/ADT/ScopedHashTableTest.cpp:41:20: error: 'ScopedHashTableScope' may not intend to support class template argument deduction [-Werror,-Wctad-maybe-unsupported] --- llvm/unittests/ADT/ScopedHashTableTest.cpp | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/llvm/unittests/ADT/ScopedHashTableTest.cpp b/llvm/unittests/ADT/ScopedHashTableTest.cpp index 64afa948d9a17..8ce5c7cecf998 100644 --- a/llvm/unittests/ADT/ScopedHashTableTest.cpp +++ b/llvm/unittests/ADT/ScopedHashTableTest.cpp @@ -38,37 +38,45 @@ TEST_F(ScopedHashTableTest, AccessWithNoActiveScope) { } TEST_F(ScopedHashTableTest, AccessWithAScope) { - [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope( + symbolTable); EXPECT_EQ(symbolTable.count(kGlobalName), 1U); } TEST_F(ScopedHashTableTest, InsertInScope) { - [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope( + symbolTable); symbolTable.insert(kLocalName, kLocalValue); EXPECT_EQ(symbolTable.count(kLocalName), 1U); } TEST_F(ScopedHashTableTest, InsertInLinearSortedScope) { - [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); - [[maybe_unused]] ScopedHashTableScope varScope2(symbolTable); - [[maybe_unused]] ScopedHashTableScope varScope3(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope( + symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope2( + symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope3( + symbolTable); symbolTable.insert(kLocalName, kLocalValue); EXPECT_EQ(symbolTable.count(kLocalName), 1U); } TEST_F(ScopedHashTableTest, InsertInOutedScope) { { - [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope( + symbolTable); symbolTable.insert(kLocalName, kLocalValue); } EXPECT_EQ(symbolTable.count(kLocalName), 0U); } TEST_F(ScopedHashTableTest, OverrideInScope) { - [[maybe_unused]] ScopedHashTableScope funScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope funScope( + symbolTable); symbolTable.insert(kLocalName, kLocalValue); { - [[maybe_unused]] ScopedHashTableScope varScope(symbolTable); + [[maybe_unused]] ScopedHashTableScope varScope( + symbolTable); symbolTable.insert(kLocalName, kLocalValue2); EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue2); } @@ -78,11 +86,11 @@ TEST_F(ScopedHashTableTest, OverrideInScope) { TEST_F(ScopedHashTableTest, GetCurScope) { EXPECT_EQ(symbolTable.getCurScope(), &globalScope); { - ScopedHashTableScope funScope(symbolTable); - ScopedHashTableScope funScope2(symbolTable); + ScopedHashTableScope funScope(symbolTable); + ScopedHashTableScope funScope2(symbolTable); EXPECT_EQ(symbolTable.getCurScope(), &funScope2); { - ScopedHashTableScope blockScope(symbolTable); + ScopedHashTableScope blockScope(symbolTable); EXPECT_EQ(symbolTable.getCurScope(), &blockScope); } EXPECT_EQ(symbolTable.getCurScope(), &funScope2); From 104ad9258a0f93a969bf7a85ebc0c7d9c533edf1 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 18 Dec 2024 20:09:33 -0800 Subject: [PATCH 007/209] [SelectionDAG] Rename SDNode::uses() to users(). (#120499) This function is most often used in range based loops or algorithms where the iterator is implicitly dereferenced. The dereference returns an SDNode * of the user rather than SDUse * so users() is a better name. I've long beeen annoyed that we can't write a range based loop over SDUse when we need getOperandNo. I plan to rename use_iterator to user_iterator and add a use_iterator that returns SDUse& on dereference. This will make it more like IR. --- llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 10 ++- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 70 +++++++++---------- .../lib/CodeGen/SelectionDAG/InstrEmitter.cpp | 6 +- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 4 +- .../CodeGen/SelectionDAG/LegalizeTypes.cpp | 4 +- .../CodeGen/SelectionDAG/ScheduleDAGFast.cpp | 2 +- .../SelectionDAG/ScheduleDAGSDNodes.cpp | 2 +- .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 14 ++-- .../CodeGen/SelectionDAG/SelectionDAGISel.cpp | 2 +- .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 20 +++--- .../Target/AArch64/AArch64ISelLowering.cpp | 16 ++--- llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 10 +-- llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 12 ++-- llvm/lib/Target/ARM/ARMISelLowering.cpp | 14 ++-- .../Target/Hexagon/HexagonISelDAGToDAGHVX.cpp | 6 +- .../LoongArch/LoongArchISelLowering.cpp | 2 +- llvm/lib/Target/M68k/M68kISelLowering.cpp | 2 +- llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp | 2 +- llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp | 8 +-- llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 10 +-- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 58 +++++++-------- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 18 ++--- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 6 +- .../Target/SystemZ/SystemZISelDAGToDAG.cpp | 2 +- .../Target/SystemZ/SystemZISelLowering.cpp | 12 ++-- llvm/lib/Target/VE/VEISelLowering.cpp | 4 +- llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 4 +- llvm/lib/Target/X86/X86ISelLowering.cpp | 53 +++++++------- llvm/lib/Target/X86/X86ISelLoweringCall.cpp | 2 +- 29 files changed, 190 insertions(+), 185 deletions(-) diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h index 61f3c6329efce..b525872f9dd2a 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -750,7 +750,7 @@ END_TWO_BYTE_PACK() bool use_empty() const { return UseList == nullptr; } /// Return true if there is exactly one use of this node. - bool hasOneUse() const { return hasSingleElement(uses()); } + bool hasOneUse() const { return hasSingleElement(users()); } /// Return the number of uses of this node. This method takes /// time proportional to the number of uses. @@ -844,10 +844,14 @@ END_TWO_BYTE_PACK() static use_iterator use_end() { return use_iterator(nullptr); } - inline iterator_range uses() { + // Dereferencing use_iterator returns the user SDNode* making it closer to a + // user_iterator thus this function is called users() to reflect that. + // FIXME: Rename to user_iterator and introduce a use_iterator that returns + // SDUse*. + inline iterator_range users() { return make_range(use_begin(), use_end()); } - inline iterator_range uses() const { + inline iterator_range users() const { return make_range(use_begin(), use_end()); } diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 10fc8eecaff90..ebce0ebe8f81c 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -202,7 +202,7 @@ namespace { /// When an instruction is simplified, add all users of the instruction to /// the work lists because they might get more simplified now. void AddUsersToWorklist(SDNode *N) { - for (SDNode *Node : N->uses()) + for (SDNode *Node : N->users()) AddToWorklist(Node); } @@ -1113,7 +1113,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc, : N1.getConstantOperandVal(1))); if (Opc == ISD::SUB) ScalableOffset = -ScalableOffset; - if (all_of(N->uses(), [&](SDNode *Node) { + if (all_of(N->users(), [&](SDNode *Node) { if (auto *LoadStore = dyn_cast(Node); LoadStore && LoadStore->getBasePtr().getNode() == N) { TargetLoweringBase::AddrMode AM; @@ -1151,7 +1151,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc, return false; const int64_t CombinedValue = CombinedValueIntVal.getSExtValue(); - for (SDNode *Node : N->uses()) { + for (SDNode *Node : N->users()) { if (auto *LoadStore = dyn_cast(Node)) { // Is x[offset2] already not a legal addressing mode? If so then // reassociating the constants breaks nothing (we test offset2 because @@ -1176,7 +1176,7 @@ bool DAGCombiner::reassociationCanBreakAddressingModePattern(unsigned Opc, if (GA->getOpcode() == ISD::GlobalAddress && TLI.isOffsetFoldingLegal(GA)) return false; - for (SDNode *Node : N->uses()) { + for (SDNode *Node : N->users()) { auto *LoadStore = dyn_cast(Node); if (!LoadStore) return false; @@ -4720,7 +4720,7 @@ SDValue DAGCombiner::useDivRem(SDNode *Node) { SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); SDValue combined; - for (SDNode *User : Op0->uses()) { + for (SDNode *User : Op0->users()) { if (User == Node || User->getOpcode() == ISD::DELETED_NODE || User->use_empty()) continue; @@ -10369,7 +10369,7 @@ static SDValue combineShiftToMULH(SDNode *N, const SDLoc &DL, SelectionDAG &DAG, unsigned MulLoHiOp = IsSignExt ? ISD::SMUL_LOHI : ISD::UMUL_LOHI; if (!ShiftOperand.hasOneUse() && TLI.isOperationLegalOrCustom(MulLoHiOp, NarrowVT) && - llvm::any_of(ShiftOperand->uses(), UserOfLowerBits)) { + llvm::any_of(ShiftOperand->users(), UserOfLowerBits)) { return SDValue(); } @@ -13570,7 +13570,7 @@ static SDValue tryToFoldExtOfLoad(SelectionDAG &DAG, DAGCombiner &Combiner, if (NonNegZExt) { assert(ExtLoadType == ISD::ZEXTLOAD && ExtOpc == ISD::ZERO_EXTEND && "Unexpected load type or opcode"); - for (SDNode *User : N0->uses()) { + for (SDNode *User : N0->users()) { if (User->getOpcode() == ISD::SETCC) { ISD::CondCode CC = cast(User->getOperand(2))->get(); if (ISD::isSignedIntSetCC(CC)) { @@ -17673,7 +17673,7 @@ SDValue DAGCombiner::combineRepeatedFPDivisors(SDNode *N) { // Find all FDIV users of the same divisor. // Use a set because duplicates may be present in the user list. SetVector Users; - for (auto *U : N1->uses()) { + for (auto *U : N1->users()) { if (U->getOpcode() == ISD::FDIV && U->getOperand(1) == N1) { // Skip X/sqrt(X) that has not been simplified to sqrt(X) yet. if (U->getOperand(1).getOpcode() == ISD::FSQRT && @@ -18965,15 +18965,15 @@ bool DAGCombiner::CombineToPreIndexedLoadStore(SDNode *N) { // Now check for #3 and #4. bool RealUse = false; - for (SDNode *Use : Ptr->uses()) { - if (Use == N) + for (SDNode *User : Ptr->users()) { + if (User == N) continue; - if (SDNode::hasPredecessorHelper(Use, Visited, Worklist, MaxSteps)) + if (SDNode::hasPredecessorHelper(User, Visited, Worklist, MaxSteps)) return false; // If Ptr may be folded in addressing mode of other use, then it's // not profitable to do this transformation. - if (!canFoldInAddressingMode(Ptr.getNode(), Use, DAG, TLI)) + if (!canFoldInAddressingMode(Ptr.getNode(), User, DAG, TLI)) RealUse = true; } @@ -19089,19 +19089,19 @@ static bool shouldCombineToPostInc(SDNode *N, SDValue Ptr, SDNode *PtrUse, SmallPtrSet Visited; unsigned MaxSteps = SelectionDAG::getHasPredecessorMaxSteps(); - for (SDNode *Use : BasePtr->uses()) { - if (Use == Ptr.getNode()) + for (SDNode *User : BasePtr->users()) { + if (User == Ptr.getNode()) continue; // No if there's a later user which could perform the index instead. - if (isa(Use)) { + if (isa(User)) { bool IsLoad = true; bool IsMasked = false; SDValue OtherPtr; - if (getCombineLoadStoreParts(Use, ISD::POST_INC, ISD::POST_DEC, IsLoad, + if (getCombineLoadStoreParts(User, ISD::POST_INC, ISD::POST_DEC, IsLoad, IsMasked, OtherPtr, TLI)) { SmallVector Worklist; - Worklist.push_back(Use); + Worklist.push_back(User); if (SDNode::hasPredecessorHelper(N, Visited, Worklist, MaxSteps)) return false; } @@ -19109,9 +19109,9 @@ static bool shouldCombineToPostInc(SDNode *N, SDValue Ptr, SDNode *PtrUse, // If all the uses are load / store addresses, then don't do the // transformation. - if (Use->getOpcode() == ISD::ADD || Use->getOpcode() == ISD::SUB) { - for (SDNode *UseUse : Use->uses()) - if (canFoldInAddressingMode(Use, UseUse, DAG, TLI)) + if (User->getOpcode() == ISD::ADD || User->getOpcode() == ISD::SUB) { + for (SDNode *UserUser : User->users()) + if (canFoldInAddressingMode(User, UserUser, DAG, TLI)) return false; } } @@ -19136,7 +19136,7 @@ static SDNode *getPostIndexedLoadStoreOp(SDNode *N, bool &IsLoad, // nor a successor of N. Otherwise, if Op is folded that would // create a cycle. unsigned MaxSteps = SelectionDAG::getHasPredecessorMaxSteps(); - for (SDNode *Op : Ptr->uses()) { + for (SDNode *Op : Ptr->users()) { // Check for #1. if (!shouldCombineToPostInc(N, Ptr, Op, BasePtr, Offset, AM, DAG, TLI)) continue; @@ -20515,24 +20515,24 @@ bool DAGCombiner::isMulAddWithConstProfitable(SDNode *MulNode, SDValue AddNode, return true; // Walk all the users of the constant with which we're multiplying. - for (SDNode *Use : ConstNode->uses()) { - if (Use == MulNode) // This use is the one we're on right now. Skip it. + for (SDNode *User : ConstNode->users()) { + if (User == MulNode) // This use is the one we're on right now. Skip it. continue; - if (Use->getOpcode() == ISD::MUL) { // We have another multiply use. + if (User->getOpcode() == ISD::MUL) { // We have another multiply use. SDNode *OtherOp; SDNode *MulVar = AddNode.getOperand(0).getNode(); // OtherOp is what we're multiplying against the constant. - if (Use->getOperand(0) == ConstNode) - OtherOp = Use->getOperand(1).getNode(); + if (User->getOperand(0) == ConstNode) + OtherOp = User->getOperand(1).getNode(); else - OtherOp = Use->getOperand(0).getNode(); + OtherOp = User->getOperand(0).getNode(); // Check to see if multiply is with the same operand of our "add". // // ConstNode = CONST - // Use = ConstNode * A <-- visiting Use. OtherOp is A. + // User = ConstNode * A <-- visiting User. OtherOp is A. // ... // AddNode = (A + c1) <-- MulVar is A. // = AddNode * ConstNode <-- current visiting instruction. @@ -20550,7 +20550,7 @@ bool DAGCombiner::isMulAddWithConstProfitable(SDNode *MulNode, SDValue AddNode, // ... = AddNode * ConstNode <-- current visiting instruction. // ... // OtherOp = (A + c2) - // Use = OtherOp * ConstNode <-- visiting Use. + // User = OtherOp * ConstNode <-- visiting User. // // If we make this transformation, we will have a common // multiply (CONST * A) after we also do the same transformation @@ -22902,7 +22902,7 @@ bool DAGCombiner::refineExtractVectorEltIntoMultipleNarrowExtractVectorElts( // Did we fail to model any of the users of the Producer? bool ProducerIsLeaf = false; // Look at each user of this Producer. - for (SDNode *User : E.Producer->uses()) { + for (SDNode *User : E.Producer->users()) { switch (User->getOpcode()) { // TODO: support ISD::BITCAST // TODO: support ISD::ANY_EXTEND @@ -23176,14 +23176,14 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { // If only EXTRACT_VECTOR_ELT nodes use the source vector we can // simplify it based on the (valid) extraction indices. - if (llvm::all_of(VecOp->uses(), [&](SDNode *Use) { + if (llvm::all_of(VecOp->users(), [&](SDNode *Use) { return Use->getOpcode() == ISD::EXTRACT_VECTOR_ELT && Use->getOperand(0) == VecOp && isa(Use->getOperand(1)); })) { APInt DemandedElts = APInt::getZero(NumElts); - for (SDNode *Use : VecOp->uses()) { - auto *CstElt = cast(Use->getOperand(1)); + for (SDNode *User : VecOp->users()) { + auto *CstElt = cast(User->getOperand(1)); if (CstElt->getAPIntValue().ult(NumElts)) DemandedElts.setBit(CstElt->getZExtValue()); } @@ -27302,7 +27302,7 @@ SDValue DAGCombiner::visitGET_FPENV_MEM(SDNode *N) { // Check if the memory, where FP state is written to, is used only in a single // load operation. LoadSDNode *LdNode = nullptr; - for (auto *U : Ptr->uses()) { + for (auto *U : Ptr->users()) { if (U == N) continue; if (auto *Ld = dyn_cast(U)) { @@ -27352,7 +27352,7 @@ SDValue DAGCombiner::visitSET_FPENV_MEM(SDNode *N) { // Check if the address of FP state is used also in a store operation only. StoreSDNode *StNode = nullptr; - for (auto *U : Ptr->uses()) { + for (auto *U : Ptr->users()) { if (U == N) continue; if (auto *St = dyn_cast(U)) { diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp index 9c7085cc7e7a8..8e313fb21eede 100644 --- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -105,7 +105,7 @@ void InstrEmitter::EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, if (TLI->isTypeLegal(VT)) UseRC = TLI->getRegClassFor(VT, Node->isDivergent()); - for (SDNode *User : Node->uses()) { + for (SDNode *User : Node->users()) { bool Match = true; if (User->getOpcode() == ISD::CopyToReg && User->getOperand(2).getNode() == Node && @@ -225,7 +225,7 @@ void InstrEmitter::CreateVirtualRegisters(SDNode *Node, } if (!VRBase && !IsClone && !IsCloned) - for (SDNode *User : Node->uses()) { + for (SDNode *User : Node->users()) { if (User->getOpcode() == ISD::CopyToReg && User->getOperand(2).getNode() == Node && User->getOperand(2).getResNo() == i) { @@ -502,7 +502,7 @@ void InstrEmitter::EmitSubregNode(SDNode *Node, VRBaseMapType &VRBaseMap, // If the node is only used by a CopyToReg and the dest reg is a vreg, use // the CopyToReg'd destination register instead of creating a new vreg. - for (SDNode *User : Node->uses()) { + for (SDNode *User : Node->users()) { if (User->getOpcode() == ISD::CopyToReg && User->getOperand(2).getNode() == Node) { Register DestReg = cast(User->getOperand(1))->getReg(); diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index ca87168929f96..595a410101eca 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1394,7 +1394,7 @@ SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { Visited.insert(Op.getNode()); Worklist.push_back(Idx.getNode()); SDValue StackPtr, Ch; - for (SDNode *User : Vec.getNode()->uses()) { + for (SDNode *User : Vec.getNode()->users()) { if (StoreSDNode *ST = dyn_cast(User)) { if (ST->isIndexed() || ST->isTruncatingStore() || ST->getValue() != Vec) @@ -2293,7 +2293,7 @@ static bool useSinCos(SDNode *Node) { ? ISD::FCOS : ISD::FSIN; SDValue Op0 = Node->getOperand(0); - for (const SDNode *User : Op0.getNode()->uses()) { + for (const SDNode *User : Op0.getNode()->users()) { if (User == Node) continue; // The other user might have been turned into sincos already. diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp index cb6d3fe4db8a4..c7d29ec1a836c 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp @@ -189,7 +189,7 @@ void DAGTypeLegalizer::PerformExpensiveChecks() { #ifndef NDEBUG // Checked that NewNodes are only used by other NewNodes. for (SDNode *N : NewNodes) { - for (SDNode *U : N->uses()) + for (SDNode *U : N->users()) assert(U->getNodeId() == NewNode && "NewNode used by non-NewNode!"); } #endif @@ -399,7 +399,7 @@ bool DAGTypeLegalizer::run() { assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?"); N->setNodeId(Processed); - for (SDNode *User : N->uses()) { + for (SDNode *User : N->users()) { int NodeId = User->getNodeId(); // This node has two options: it can either be a new node or its Node ID diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp index 70a7438440191..26eba4b257fb9 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp @@ -756,7 +756,7 @@ void ScheduleDAGLinearize::Schedule() { // Glue user must be scheduled together with the glue operand. So other // users of the glue operand must be treated as its users. SDNode *ImmGUser = Glue->getGluedUser(); - for (const SDNode *U : Glue->uses()) + for (const SDNode *U : Glue->users()) if (U == ImmGUser) --Degree; GUser->setNodeId(UDegree + Degree); diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 31939ae5922ec..2e59dbf2f7028 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -388,7 +388,7 @@ void ScheduleDAGSDNodes::BuildSchedUnits() { // There are either zero or one users of the Glue result. bool HasGlueUse = false; - for (SDNode *U : N->uses()) + for (SDNode *U : N->users()) if (GlueVal.isOperandOf(U)) { HasGlueUse = true; assert(N->getNodeId() == -1 && "Node already inserted!"); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 0fb5c4d5c4cb9..bd9e5d4dce8ec 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2556,7 +2556,7 @@ bool SelectionDAG::expandMultipleResultFPLibCall( // destination pointers can be used instead of creating stack allocations. SDValue StoresInChain; SmallVector ResultStores(NumResults); - for (SDNode *User : Node->uses()) { + for (SDNode *User : Node->users()) { if (!ISD::isNormalStore(User)) continue; auto *ST = cast(User); @@ -7933,7 +7933,7 @@ SDValue SelectionDAG::getStackArgumentTokenFactor(SDValue Chain) { ArgChains.push_back(Chain); // Add a chain value for each stack argument. - for (SDNode *U : getEntryNode().getNode()->uses()) + for (SDNode *U : getEntryNode().getNode()->users()) if (LoadSDNode *L = dyn_cast(U)) if (FrameIndexSDNode *FI = dyn_cast(L->getBasePtr())) if (FI->getIndex() < 0) @@ -11926,7 +11926,7 @@ void SelectionDAG::updateDivergence(SDNode *N) { bool IsDivergent = calculateDivergence(N); if (N->SDNodeBits.IsDivergent != IsDivergent) { N->SDNodeBits.IsDivergent = IsDivergent; - llvm::append_range(Worklist, N->uses()); + llvm::append_range(Worklist, N->users()); } } while (!Worklist.empty()); } @@ -11942,7 +11942,7 @@ void SelectionDAG::CreateTopologicalOrder(std::vector &Order) { } for (size_t I = 0; I != Order.size(); ++I) { SDNode *N = Order[I]; - for (auto *U : N->uses()) { + for (auto *U : N->users()) { unsigned &UnsortedOps = Degree[U]; if (0 == --UnsortedOps) Order.push_back(U); @@ -12071,7 +12071,7 @@ unsigned SelectionDAG::AssignTopologicalOrder() { checkForCycles(N, this); // N is in sorted position, so all its uses have one less operand // that needs to be sorted. - for (SDNode *P : N->uses()) { + for (SDNode *P : N->users()) { unsigned Degree = P->getNodeId(); assert(Degree != 0 && "Invalid node degree"); --Degree; @@ -12489,7 +12489,7 @@ bool SDNode::hasAnyUseOfValue(unsigned Value) const { /// isOnlyUserOf - Return true if this node is the only use of N. bool SDNode::isOnlyUserOf(const SDNode *N) const { bool Seen = false; - for (const SDNode *User : N->uses()) { + for (const SDNode *User : N->users()) { if (User == this) Seen = true; else @@ -12502,7 +12502,7 @@ bool SDNode::isOnlyUserOf(const SDNode *N) const { /// Return true if the only users of N are contained in Nodes. bool SDNode::areOnlyUsersOf(ArrayRef Nodes, const SDNode *N) { bool Seen = false; - for (const SDNode *User : N->uses()) { + for (const SDNode *User : N->users()) { if (llvm::is_contained(Nodes, User)) Seen = true; else diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 35aa7b87bc3b7..9147fb1c2badf 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1225,7 +1225,7 @@ void SelectionDAGISel::EnforceNodeIdInvariant(SDNode *Node) { while (!Nodes.empty()) { SDNode *N = Nodes.pop_back_val(); - for (auto *U : N->uses()) { + for (auto *U : N->users()) { auto UId = U->getNodeId(); if (UId > 0) { InvalidateNodeId(U); diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 5df61b3722037..ff3ca8a24fc04 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -679,9 +679,9 @@ static bool isWorthFoldingSHL(SDValue V) { // operation. If yes, do not try to fold this node into the address // computation, since the computation will be kept. const SDNode *Node = V.getNode(); - for (SDNode *UI : Node->uses()) + for (SDNode *UI : Node->users()) if (!isa(*UI)) - for (SDNode *UII : UI->uses()) + for (SDNode *UII : UI->users()) if (!isa(*UII)) return false; return true; @@ -1012,15 +1012,15 @@ bool AArch64DAGToDAGISel::SelectArithUXTXRegister(SDValue N, SDValue &Reg, /// a single pseudo-instruction for an ADRP/ADD pair so over-aggressive folding /// leads to duplicated ADRP instructions. static bool isWorthFoldingADDlow(SDValue N) { - for (auto *Use : N->uses()) { - if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && - Use->getOpcode() != ISD::ATOMIC_LOAD && - Use->getOpcode() != ISD::ATOMIC_STORE) + for (auto *User : N->users()) { + if (User->getOpcode() != ISD::LOAD && User->getOpcode() != ISD::STORE && + User->getOpcode() != ISD::ATOMIC_LOAD && + User->getOpcode() != ISD::ATOMIC_STORE) return false; // ldar and stlr have much more restrictive addressing modes (just a // register). - if (isStrongerThanMonotonic(cast(Use)->getSuccessOrdering())) + if (isStrongerThanMonotonic(cast(User)->getSuccessOrdering())) return false; } @@ -1245,7 +1245,7 @@ bool AArch64DAGToDAGISel::SelectAddrModeWRO(SDValue N, unsigned Size, // operation. If yes, do not try to fold this node into the address // computation, since the computation will be kept. const SDNode *Node = N.getNode(); - for (SDNode *UI : Node->uses()) { + for (SDNode *UI : Node->users()) { if (!isa(*UI)) return false; } @@ -1329,7 +1329,7 @@ bool AArch64DAGToDAGISel::SelectAddrModeXRO(SDValue N, unsigned Size, // operation. If yes, do not try to fold this node into the address // computation, since the computation will be kept. const SDNode *Node = N.getNode(); - for (SDNode *UI : Node->uses()) { + for (SDNode *UI : Node->users()) { if (!isa(*UI)) return false; } @@ -3031,7 +3031,7 @@ static void getUsefulBits(SDValue Op, APInt &UsefulBits, unsigned Depth) { } APInt UsersUsefulBits(UsefulBits.getBitWidth(), 0); - for (SDNode *Node : Op.getNode()->uses()) { + for (SDNode *Node : Op.getNode()->users()) { // A use cannot produce useful bits APInt UsefulBitsForUse = APInt(UsefulBits); getUsefulBitsForUse(Node, UsefulBitsForUse, Op, Depth); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index cb6ba06bd4425..5865dbe1307ba 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -6464,7 +6464,7 @@ bool AArch64TargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { return false; unsigned NumExtMaskedLoads = 0; - for (auto *U : Ld->getMask()->uses()) + for (auto *U : Ld->getMask()->users()) if (isa(U)) NumExtMaskedLoads++; @@ -8559,7 +8559,7 @@ SDValue AArch64TargetLowering::addTokenForArgument(SDValue Chain, ArgChains.push_back(Chain); // Add a chain value for each stack argument corresponding - for (SDNode *U : DAG.getEntryNode().getNode()->uses()) + for (SDNode *U : DAG.getEntryNode().getNode()->users()) if (LoadSDNode *L = dyn_cast(U)) if (FrameIndexSDNode *FI = dyn_cast(L->getBasePtr())) if (FI->getIndex() < 0) { @@ -19586,7 +19586,7 @@ static SDValue performANDSETCCCombine(SDNode *N, // Checks if the current node (N) is used by any SELECT instruction and // returns an empty SDValue to avoid applying the optimization to prevent // incorrect results - for (auto U : N->uses()) + for (auto U : N->users()) if (U->getOpcode() == ISD::SELECT) return SDValue(); @@ -24761,7 +24761,7 @@ static SDValue tryToWidenSetCCOperands(SDNode *Op, SelectionDAG &DAG) { EVT UseMVT = FirstUse->getValueType(0); if (UseMVT.getScalarSizeInBits() <= Op0MVT.getScalarSizeInBits()) return SDValue(); - if (any_of(Op->uses(), [&UseMVT](const SDNode *N) { + if (any_of(Op->users(), [&UseMVT](const SDNode *N) { return N->getOpcode() != ISD::VSELECT || N->getValueType(0) != UseMVT; })) return SDValue(); @@ -25335,7 +25335,7 @@ static SDValue performGlobalAddressCombine(SDNode *N, SelectionDAG &DAG, return SDValue(); uint64_t MinOffset = -1ull; - for (SDNode *N : GN->uses()) { + for (SDNode *N : GN->users()) { if (N->getOpcode() != ISD::ADD) return SDValue(); auto *C = dyn_cast(N->getOperand(0)); @@ -26054,7 +26054,7 @@ static SDValue tryCombineMULLWithUZP1(SDNode *N, HasFoundMULLow = false; // Find ExtractLow. - for (SDNode *User : ExtractHighSrcVec.getNode()->uses()) { + for (SDNode *User : ExtractHighSrcVec.getNode()->users()) { if (User == ExtractHigh.getNode()) continue; @@ -26561,7 +26561,7 @@ bool AArch64TargetLowering::isUsedByReturnOnly(SDNode *N, return false; bool HasRet = false; - for (SDNode *Node : Copy->uses()) { + for (SDNode *Node : Copy->users()) { if (Node->getOpcode() != AArch64ISD::RET_GLUE) return false; HasRet = true; @@ -29650,7 +29650,7 @@ Value *AArch64TargetLowering::createComplexDeinterleavingIR( bool AArch64TargetLowering::preferScalarizeSplat(SDNode *N) const { unsigned Opc = N->getOpcode(); if (ISD::isExtOpcode(Opc)) { - if (any_of(N->uses(), + if (any_of(N->users(), [&](SDNode *Use) { return Use->getOpcode() == ISD::MUL; })) return false; } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 48e9af9fe507f..c129759f3d3c7 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -772,7 +772,7 @@ bool AMDGPUTargetLowering::allUsesHaveSourceMods(const SDNode *N, assert(!N->use_empty()); // XXX - Should this limit number of uses to check? - for (const SDNode *U : N->uses()) { + for (const SDNode *U : N->users()) { if (!hasSourceMods(U)) return false; @@ -1348,7 +1348,7 @@ SDValue AMDGPUTargetLowering::addTokenForArgument(SDValue Chain, ArgChains.push_back(Chain); // Add a chain value for each stack argument corresponding - for (SDNode *U : DAG.getEntryNode().getNode()->uses()) { + for (SDNode *U : DAG.getEntryNode().getNode()->users()) { if (LoadSDNode *L = dyn_cast(U)) { if (FrameIndexSDNode *FI = dyn_cast(L->getBasePtr())) { if (FI->getIndex() < 0) { @@ -3814,7 +3814,7 @@ static SDValue constantFoldBFE(SelectionDAG &DAG, IntTy Src0, uint32_t Offset, } static bool hasVolatileUser(SDNode *Val) { - for (SDNode *U : Val->uses()) { + for (SDNode *U : Val->users()) { if (MemSDNode *M = dyn_cast(U)) { if (M->isVolatile()) return true; @@ -4338,7 +4338,7 @@ SDValue AMDGPUTargetLowering::performMulCombine(SDNode *N, if (!AddOp) return SDValue(); - if (V.hasOneUse() || all_of(V->uses(), [](const SDNode *U) -> bool { + if (V.hasOneUse() || all_of(V->users(), [](const SDNode *U) -> bool { return U->getOpcode() == ISD::MUL; })) return AddOp; @@ -4927,7 +4927,7 @@ SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N, SDValue Neg = DAG.getNode(ISD::FNEG, SL, VT, Res); DAG.ReplaceAllUsesWith(N0, Neg); - for (SDNode *U : Neg->uses()) + for (SDNode *U : Neg->users()) DCI.AddToWorklist(U); } diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 7da93f90341d2..2b8cc5b4e33a4 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -12544,21 +12544,21 @@ SDValue SITargetLowering::performOrCombine(SDNode *N, return true; // If we have any non-vectorized use, then it is a candidate for v_perm - for (auto *VUse : OrUse->uses()) { - if (!VUse->getValueType(0).isVector()) + for (auto *VUser : OrUse->users()) { + if (!VUser->getValueType(0).isVector()) return true; // If the use of a vector is a store, then combining via a v_perm // is beneficial. // TODO -- whitelist more uses for (auto VectorwiseOp : {ISD::STORE, ISD::CopyToReg, ISD::CopyFromReg}) - if (VUse->getOpcode() == VectorwiseOp) + if (VUser->getOpcode() == VectorwiseOp) return true; } return false; }; - if (!any_of(N->uses(), usesCombinedOperand)) + if (!any_of(N->users(), usesCombinedOperand)) return SDValue(); uint32_t LHSMask = getPermuteMask(LHS); @@ -13895,10 +13895,10 @@ SDValue SITargetLowering::tryFoldToMad64_32(SDNode *N, // part of full-rate 64-bit ops). if (!Subtarget->hasFullRate64Ops()) { unsigned NumUsers = 0; - for (SDNode *Use : LHS->uses()) { + for (SDNode *User : LHS->users()) { // There is a use that does not feed into addition, so the multiply can't // be removed. We prefer MUL + ADD + ADDC over MAD + MUL. - if (Use->getOpcode() != ISD::ADD) + if (User->getOpcode() != ISD::ADD) return SDValue(); // We prefer 2xMAD over MUL + 2xADD + 2xADDC (code density), and prefer diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 2b20154042fe2..764d3c879f2d6 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -3467,7 +3467,7 @@ bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { SDNode *VMov = Copy; // f64 returned in a pair of GPRs. SmallPtrSet Copies; - for (SDNode *U : VMov->uses()) { + for (SDNode *U : VMov->users()) { if (U->getOpcode() != ISD::CopyToReg) return false; Copies.insert(U); @@ -3475,7 +3475,7 @@ bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { if (Copies.size() > 2) return false; - for (SDNode *U : VMov->uses()) { + for (SDNode *U : VMov->users()) { SDValue UseChain = U->getOperand(0); if (Copies.count(UseChain.getNode())) // Second CopyToReg @@ -3507,7 +3507,7 @@ bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { } bool HasRet = false; - for (const SDNode *U : Copy->uses()) { + for (const SDNode *U : Copy->users()) { if (U->getOpcode() != ARMISD::RET_GLUE && U->getOpcode() != ARMISD::INTRET_GLUE) return false; @@ -7958,7 +7958,7 @@ SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, // generate a vdup of the constant. if (ST->hasMVEIntegerOps() && VT.getScalarSizeInBits() == SplatBitSize && (SplatBitSize == 8 || SplatBitSize == 16 || SplatBitSize == 32) && - all_of(BVN->uses(), + all_of(BVN->users(), [BVN](const SDNode *U) { return IsQRMVEInstruction(U, BVN); })) { EVT DupVT = SplatBitSize == 32 ? MVT::v4i32 : SplatBitSize == 16 ? MVT::v8i16 @@ -13970,7 +13970,7 @@ static SDValue PerformSHLSimplify(SDNode *N, return SDValue(); // Check that all the users could perform the shl themselves. - for (auto *U : N->uses()) { + for (auto *U : N->users()) { switch(U->getOpcode()) { default: return SDValue(); @@ -15574,13 +15574,13 @@ PerformExtractEltToVMOVRRD(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { return SDValue(); // Find another extract, of Lane + 1 - auto OtherIt = find_if(Op0->uses(), [&](SDNode *V) { + auto OtherIt = find_if(Op0->users(), [&](SDNode *V) { return V->getOpcode() == ISD::EXTRACT_VECTOR_ELT && isa(V->getOperand(1)) && V->getConstantOperandVal(1) == Lane + 1 && V->getOperand(0).getResNo() == ResNo; }); - if (OtherIt == Op0->uses().end()) + if (OtherIt == Op0->users().end()) return SDValue(); // For float extracts, we need to be converting to a i32 for both vector diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp index c1937ff70f366..db9aa7e18f5e7 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp @@ -1756,7 +1756,7 @@ void HvxSelector::select(SDNode *ISelN) { // Don't want to select N0 if it's shared with another node, except if // it's shared with other ISELs. auto IsISelN = [](SDNode *T) { return T->getOpcode() == HexagonISD::ISEL; }; - if (llvm::all_of(N0->uses(), IsISelN)) + if (llvm::all_of(N0->users(), IsISelN)) SubNodes.insert(N0); } if (SubNodes.empty()) { @@ -1775,7 +1775,7 @@ void HvxSelector::select(SDNode *ISelN) { return true; if (T->use_empty() || NonDom.count(T)) return false; - for (SDNode *U : T->uses()) { + for (SDNode *U : T->users()) { // If T is reachable from a known non-dominated node, then T itself // is non-dominated. if (!Rec(U, Rec)) { @@ -1814,7 +1814,7 @@ void HvxSelector::select(SDNode *ISelN) { for (unsigned I = 0; I != TmpQ.size(); ++I) { SDNode *S = TmpQ[I]; - for (SDNode *U : S->uses()) { + for (SDNode *U : S->users()) { if (U == ISelN) continue; auto F = OpCount.find(U); diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 104e601de044b..e32ed41c2893c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -5351,7 +5351,7 @@ bool LoongArchTargetLowering::isUsedByReturnOnly(SDNode *N, // The copy must be used by a LoongArchISD::RET, and nothing else. bool HasRet = false; - for (SDNode *Node : Copy->uses()) { + for (SDNode *Node : Copy->users()) { if (Node->getOpcode() != LoongArchISD::RET) return false; HasRet = true; diff --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp index ff966baecf27d..98ed46d91da60 100644 --- a/llvm/lib/Target/M68k/M68kISelLowering.cpp +++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp @@ -1990,7 +1990,7 @@ SDValue M68kTargetLowering::EmitTest(SDValue Op, unsigned M68kCC, case ISD::XOR: // Due to the ISEL shortcoming noted above, be conservative if this op is // likely to be selected as part of a load-modify-store instruction. - for (const auto *U : Op.getNode()->uses()) + for (const auto *U : Op.getNode()->users()) if (U->getOpcode() == ISD::STORE) goto default_case; diff --git a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp index 94e90a84a2d41..c838b21cbf75e 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp @@ -318,7 +318,7 @@ bool NVPTXDAGToDAGISel::tryEXTRACT_VECTOR_ELEMENT(SDNode *N) { return false; // Find and record all uses of this vector that extract element 0 or 1. SmallVector E0, E1; - for (auto *U : Vector.getNode()->uses()) { + for (auto *U : Vector.getNode()->users()) { if (U->getOpcode() != ISD::EXTRACT_VECTOR_ELT) continue; if (U->getOperand(0) != Vector) diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp index a033a8247fac5..5c1f717694a4c 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -4495,7 +4495,7 @@ PerformFADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, // int numUses = 0; int nonAddCount = 0; - for (const SDNode *User : N0.getNode()->uses()) { + for (const SDNode *User : N0.getNode()->users()) { numUses++; if (User->getOpcode() != ISD::FADD) ++nonAddCount; @@ -4523,7 +4523,7 @@ PerformFADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, opIsLive = true; if (!opIsLive) - for (const SDNode *User : left->uses()) { + for (const SDNode *User : left->users()) { int orderNo3 = User->getIROrder(); if (orderNo3 > orderNo) { opIsLive = true; @@ -4532,7 +4532,7 @@ PerformFADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, } if (!opIsLive) - for (const SDNode *User : right->uses()) { + for (const SDNode *User : right->users()) { int orderNo3 = User->getIROrder(); if (orderNo3 > orderNo) { opIsLive = true; @@ -4730,7 +4730,7 @@ static SDValue PerformREMCombine(SDNode *N, const SDValue &Num = N->getOperand(0); const SDValue &Den = N->getOperand(1); - for (const SDNode *U : Num->uses()) { + for (const SDNode *U : Num->users()) { if (U->getOpcode() == DivOpc && U->getOperand(0) == Num && U->getOperand(1) == Den) { // Num % Den -> Num - (Num / Den) * Den diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 2475b8ad11f10..277c1414d7160 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -750,7 +750,7 @@ static bool canOptimizeTLSDFormToXForm(SelectionDAG *CurDAG, SDValue Base) { // Base is expected to be an ADD_TLS node. if (Base.getOpcode() != PPCISD::ADD_TLS) return false; - for (auto *ADDTLSUse : Base.getNode()->uses()) { + for (auto *ADDTLSUse : Base.getNode()->users()) { // The optimization to convert the D-Form load/store into its X-Form // counterpart should only occur if the source value offset of the load/ // store is 0. This also means that The offset should always be undefined. @@ -3986,7 +3986,7 @@ static bool allUsesExtend(SDValue Compare, SelectionDAG *CurDAG) { return true; // We want the value in a GPR if it is being extended, used for a select, or // used in logical operations. - for (auto *CompareUse : Compare.getNode()->uses()) + for (auto *CompareUse : Compare.getNode()->users()) if (CompareUse->getOpcode() != ISD::SIGN_EXTEND && CompareUse->getOpcode() != ISD::ZERO_EXTEND && CompareUse->getOpcode() != ISD::SELECT && @@ -6701,7 +6701,7 @@ void PPCDAGToDAGISel::PostprocessISelDAG() { // be folded with the isel so that we don't need to materialize a register // containing zero. bool PPCDAGToDAGISel::AllUsersSelectZero(SDNode *N) { - for (const SDNode *User : N->uses()) { + for (const SDNode *User : N->users()) { if (!User->isMachineOpcode()) return false; if (User->getMachineOpcode() != PPC::SELECT_I4 && @@ -6731,7 +6731,7 @@ bool PPCDAGToDAGISel::AllUsersSelectZero(SDNode *N) { void PPCDAGToDAGISel::SwapAllSelectUsers(SDNode *N) { SmallVector ToReplace; - for (SDNode *User : N->uses()) { + for (SDNode *User : N->users()) { assert((User->getMachineOpcode() == PPC::SELECT_I4 || User->getMachineOpcode() == PPC::SELECT_I8) && "Must have all select users"); @@ -7382,7 +7382,7 @@ void PPCDAGToDAGISel::PeepholePPC64ZExt() { // (except for the original INSERT_SUBREG), then abort the transformation. bool OutsideUse = false; for (SDNode *PN : ToPromote) { - for (SDNode *UN : PN->uses()) { + for (SDNode *UN : PN->users()) { if (!ToPromote.count(UN) && UN != ISR.getNode()) { OutsideUse = true; break; diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 69bc2cce6c2c7..199e1f41cfc05 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -2687,7 +2687,7 @@ static bool provablyDisjointOr(SelectionDAG &DAG, const SDValue &N) { bool PPCTargetLowering::SelectAddressEVXRegReg(SDValue N, SDValue &Base, SDValue &Index, SelectionDAG &DAG) const { - for (SDNode *U : N->uses()) { + for (SDNode *U : N->users()) { if (MemSDNode *Memop = dyn_cast(U)) { if (Memop->getMemoryVT() == MVT::f64) { Base = N.getOperand(0); @@ -12033,7 +12033,7 @@ SDValue PPCTargetLowering::LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const { SDValue PPCTargetLowering::LowerUaddo(SDValue Op, SelectionDAG &DAG) const { // Default to target independent lowering if there is a logical user of the // carry-bit. - for (SDNode *U : Op->uses()) { + for (SDNode *U : Op->users()) { if (U->getOpcode() == ISD::SELECT) return SDValue(); if (ISD::isBitwiseLogicOp(U->getOpcode())) { @@ -14290,7 +14290,7 @@ static bool findConsecutiveLoad(LoadSDNode *LD, SelectionDAG &DAG) { if (isConsecutiveLS(ChainLD, LD, VT.getStoreSize(), 1, DAG)) return true; - for (SDNode *U : LoadRoot->uses()) + for (SDNode *U : LoadRoot->users()) if (((isa(U) && cast(U)->getChain().getNode() == LoadRoot) || U->getOpcode() == ISD::TokenFactor) && @@ -14352,7 +14352,7 @@ SDValue PPCTargetLowering::ConvertSETCCToSubtract(SDNode *N, // If all users of SETCC extend its value to a legal integer type // then we replace SETCC with a subtraction - for (const SDNode *U : N->uses()) + for (const SDNode *U : N->users()) if (U->getOpcode() != ISD::ZERO_EXTEND) return SDValue(); @@ -14531,7 +14531,7 @@ SDValue PPCTargetLowering::DAGCombineTruncBoolExt(SDNode *N, if (isa(Inputs[i])) continue; - for (const SDNode *User : Inputs[i].getNode()->uses()) { + for (const SDNode *User : Inputs[i].getNode()->users()) { if (User != N && !Visited.count(User)) return SDValue(); @@ -14552,7 +14552,7 @@ SDValue PPCTargetLowering::DAGCombineTruncBoolExt(SDNode *N, } for (unsigned i = 0, ie = PromOps.size(); i != ie; ++i) { - for (const SDNode *User : PromOps[i].getNode()->uses()) { + for (const SDNode *User : PromOps[i].getNode()->users()) { if (User != N && !Visited.count(User)) return SDValue(); @@ -14736,7 +14736,7 @@ SDValue PPCTargetLowering::DAGCombineExtBoolTrunc(SDNode *N, if (isa(Inputs[i])) continue; - for (SDNode *User : Inputs[i].getNode()->uses()) { + for (SDNode *User : Inputs[i].getNode()->users()) { if (User != N && !Visited.count(User)) return SDValue(); @@ -14758,7 +14758,7 @@ SDValue PPCTargetLowering::DAGCombineExtBoolTrunc(SDNode *N, } for (unsigned i = 0, ie = PromOps.size(); i != ie; ++i) { - for (SDNode *User : PromOps[i].getNode()->uses()) { + for (SDNode *User : PromOps[i].getNode()->users()) { if (User != N && !Visited.count(User)) return SDValue(); @@ -16556,35 +16556,35 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N, APInt::getAllOnes(Bits /* alignment */) .zext(Add.getScalarValueSizeInBits()))) { SDNode *BasePtr = Add->getOperand(0).getNode(); - for (SDNode *U : BasePtr->uses()) { - if (U->getOpcode() == ISD::INTRINSIC_WO_CHAIN && - U->getConstantOperandVal(0) == IID) { - // We've found another LVSL/LVSR, and this address is an aligned - // multiple of that one. The results will be the same, so use the - // one we've just found instead. - - return SDValue(U, 0); - } + for (SDNode *U : BasePtr->users()) { + if (U->getOpcode() == ISD::INTRINSIC_WO_CHAIN && + U->getConstantOperandVal(0) == IID) { + // We've found another LVSL/LVSR, and this address is an aligned + // multiple of that one. The results will be the same, so use the + // one we've just found instead. + + return SDValue(U, 0); + } } } if (isa(Add->getOperand(1))) { SDNode *BasePtr = Add->getOperand(0).getNode(); - for (SDNode *U : BasePtr->uses()) { - if (U->getOpcode() == ISD::ADD && - isa(U->getOperand(1)) && - (Add->getConstantOperandVal(1) - U->getConstantOperandVal(1)) % - (1ULL << Bits) == - 0) { - SDNode *OtherAdd = U; - for (SDNode *V : OtherAdd->uses()) { - if (V->getOpcode() == ISD::INTRINSIC_WO_CHAIN && - V->getConstantOperandVal(0) == IID) { - return SDValue(V, 0); + for (SDNode *U : BasePtr->users()) { + if (U->getOpcode() == ISD::ADD && + isa(U->getOperand(1)) && + (Add->getConstantOperandVal(1) - U->getConstantOperandVal(1)) % + (1ULL << Bits) == + 0) { + SDNode *OtherAdd = U; + for (SDNode *V : OtherAdd->users()) { + if (V->getOpcode() == ISD::INTRINSIC_WO_CHAIN && + V->getConstantOperandVal(0) == IID) { + return SDValue(V, 0); + } } } } - } } } diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index ccf34b8a6b2b0..4393d33021760 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -2614,21 +2614,21 @@ static bool selectConstantAddr(SelectionDAG *CurDAG, const SDLoc &DL, // Is this ADD instruction only used as the base pointer of scalar loads and // stores? static bool isWorthFoldingAdd(SDValue Add) { - for (auto *Use : Add->uses()) { - if (Use->getOpcode() != ISD::LOAD && Use->getOpcode() != ISD::STORE && - Use->getOpcode() != ISD::ATOMIC_LOAD && - Use->getOpcode() != ISD::ATOMIC_STORE) + for (auto *User : Add->users()) { + if (User->getOpcode() != ISD::LOAD && User->getOpcode() != ISD::STORE && + User->getOpcode() != ISD::ATOMIC_LOAD && + User->getOpcode() != ISD::ATOMIC_STORE) return false; - EVT VT = cast(Use)->getMemoryVT(); + EVT VT = cast(User)->getMemoryVT(); if (!VT.isScalarInteger() && VT != MVT::f16 && VT != MVT::f32 && VT != MVT::f64) return false; // Don't allow stores of the value. It must be used as the address. - if (Use->getOpcode() == ISD::STORE && - cast(Use)->getValue() == Add) + if (User->getOpcode() == ISD::STORE && + cast(User)->getValue() == Add) return false; - if (Use->getOpcode() == ISD::ATOMIC_STORE && - cast(Use)->getVal() == Add) + if (User->getOpcode() == ISD::ATOMIC_STORE && + cast(User)->getVal() == Add) return false; } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index affc29ec18ff7..9383e700ade86 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -16310,7 +16310,7 @@ static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, // All users should be a shift by constant less than or equal to 32. This // ensures we'll do this optimization for each of them to produce an // add/sub+sext_inreg they can all share. - for (SDNode *U : N0->uses()) { + for (SDNode *U : N0->users()) { if (U->getOpcode() != ISD::SRA || !isa(U->getOperand(1)) || U->getConstantOperandVal(1) > 32) @@ -18374,7 +18374,7 @@ bool RISCVTargetLowering::isDesirableToCommuteWithShift( // LD/ST, it can still complete the folding optimization operation performed // above. auto isUsedByLdSt = [](const SDNode *X, const SDNode *User) { - for (SDNode *Use : X->uses()) { + for (SDNode *Use : X->users()) { // This use is the one we're on right now. Skip it if (Use == User || Use->getOpcode() == ISD::SELECT) continue; @@ -20511,7 +20511,7 @@ bool RISCVTargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { // The copy must be used by a RISCVISD::RET_GLUE, and nothing else. bool HasRet = false; - for (SDNode *Node : Copy->uses()) { + for (SDNode *Node : Copy->users()) { if (Node->getOpcode() != RISCVISD::RET_GLUE) return false; HasRet = true; diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index 403d238aa5b52..210e3c5426f46 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -1890,7 +1890,7 @@ SystemZDAGToDAGISel::IsProfitableToFold(SDValue N, SDNode *U, SDNode *CCRegUser = nullptr; if (CCUser->getOpcode() == ISD::CopyToReg || cast(CCUser->getOperand(1))->getReg() == SystemZ::CC) { - for (auto *U : CCUser->uses()) { + for (auto *U : CCUser->users()) { if (CCRegUser == nullptr) CCRegUser = U; else if (CCRegUser != U) diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index becc3936eef89..47008af3479ee 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2910,7 +2910,7 @@ static void adjustForSubtraction(SelectionDAG &DAG, const SDLoc &DL, Comparison &C) { if (C.CCMask == SystemZ::CCMASK_CMP_EQ || C.CCMask == SystemZ::CCMASK_CMP_NE) { - for (SDNode *N : C.Op0->uses()) { + for (SDNode *N : C.Op0->users()) { if (N->getOpcode() == ISD::SUB && ((N->getOperand(0) == C.Op0 && N->getOperand(1) == C.Op1) || (N->getOperand(0) == C.Op1 && N->getOperand(1) == C.Op0))) { @@ -2936,7 +2936,7 @@ static void adjustForFNeg(Comparison &C) { return; auto *C1 = dyn_cast(C.Op1); if (C1 && C1->isZero()) { - for (SDNode *N : C.Op0->uses()) { + for (SDNode *N : C.Op0->users()) { if (N->getOpcode() == ISD::FNEG) { C.Op0 = SDValue(N, 0); C.CCMask = SystemZ::reverseCCMask(C.CCMask); @@ -2960,7 +2960,7 @@ static void adjustForLTGFR(Comparison &C) { if (C1 && C1->getZExtValue() == 32) { SDValue ShlOp0 = C.Op0.getOperand(0); // See whether X has any SIGN_EXTEND_INREG uses. - for (SDNode *N : ShlOp0->uses()) { + for (SDNode *N : ShlOp0->users()) { if (N->getOpcode() == ISD::SIGN_EXTEND_INREG && cast(N->getOperand(1))->getVT() == MVT::i32) { C.Op0 = SDValue(N, 0); @@ -7289,7 +7289,7 @@ static bool isVectorElementSwap(ArrayRef M, EVT VT) { } static bool isOnlyUsedByStores(SDValue StoredVal, SelectionDAG &DAG) { - for (auto *U : StoredVal->uses()) { + for (auto *U : StoredVal->users()) { if (StoreSDNode *ST = dyn_cast(U)) { EVT CurrMemVT = ST->getMemoryVT().getScalarType(); if (CurrMemVT.isRound() && CurrMemVT.getStoreSize() <= 16) @@ -7668,7 +7668,7 @@ SDValue SystemZTargetLowering::combineFP_ROUND( Op0.getOperand(1).getOpcode() == ISD::Constant && Op0.getConstantOperandVal(1) == 0) { SDValue Vec = Op0.getOperand(0); - for (auto *U : Vec->uses()) { + for (auto *U : Vec->users()) { if (U != Op0.getNode() && U->hasOneUse() && U->getOpcode() == ISD::EXTRACT_VECTOR_ELT && U->getOperand(0) == Vec && @@ -7732,7 +7732,7 @@ SDValue SystemZTargetLowering::combineFP_EXTEND( Op0.getOperand(1).getOpcode() == ISD::Constant && Op0.getConstantOperandVal(1) == 0) { SDValue Vec = Op0.getOperand(0); - for (auto *U : Vec->uses()) { + for (auto *U : Vec->users()) { if (U != Op0.getNode() && U->hasOneUse() && U->getOpcode() == ISD::EXTRACT_VECTOR_ELT && U->getOperand(0) == Vec && diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp index a56b5a2ac9a3e..87c1625c11454 100644 --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -2951,7 +2951,7 @@ static bool isI32Insn(const SDNode *User, const SDNode *N) { static bool isI32InsnAllUses(const SDNode *User, const SDNode *N) { // Check all use of User node. If all of them are safe, optimize // truncate to extract_subreg. - for (const SDNode *U : User->uses()) { + for (const SDNode *U : User->users()) { switch (U->getOpcode()) { default: // If the use is an instruction which treats the source operand as i32, @@ -3002,7 +3002,7 @@ SDValue VETargetLowering::combineTRUNCATE(SDNode *N, return SDValue(); // Check all use of this TRUNCATE. - for (const SDNode *User : N->uses()) { + for (const SDNode *User : N->users()) { // Make sure that we're not going to replace TRUNCATE for non i32 // instructions. // diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 76ef207f7d47d..bb20e6ecf281b 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -370,7 +370,7 @@ namespace { return false; // Walk all the users of the immediate. - for (const SDNode *User : N->uses()) { + for (const SDNode *User : N->users()) { if (UseCount >= 2) break; @@ -1095,7 +1095,7 @@ void X86DAGToDAGISel::PreprocessISelDAG() { SDNode *MaxLd = nullptr; SDValue Ptr = Ld->getBasePtr(); SDValue Chain = Ld->getChain(); - for (SDNode *User : Ptr->uses()) { + for (SDNode *User : Ptr->users()) { auto *UserLd = dyn_cast(User); MVT UserVT = User->getSimpleValueType(0); if (User != N && UserLd && ISD::isNormalLoad(User) && diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 35c0974733aba..4bd65dc6ade40 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -7397,7 +7397,7 @@ static Constant *getConstantVector(MVT VT, const APInt &SplatValue, } static bool isFoldableUseOfShuffle(SDNode *N) { - for (auto *U : N->uses()) { + for (auto *U : N->users()) { unsigned Opc = U->getOpcode(); // VPERMV/VPERMV3 shuffles can never fold their index operands. if (Opc == X86ISD::VPERMV && U->getOperand(0).getNode() == N) @@ -16004,7 +16004,7 @@ static SDValue lowerShufflePairAsUNPCKAndPermute(const SDLoc &DL, MVT VT, // Find the intersection between shuffle users of V1 and V2. SmallVector Shuffles; - for (SDNode *User : V1->uses()) + for (SDNode *User : V1->users()) if (User->getOpcode() == ISD::VECTOR_SHUFFLE && User->getOperand(0) == V1 && User->getOperand(1) == V2) Shuffles.push_back(User); @@ -18280,7 +18280,7 @@ static APInt getExtractedDemandedElts(SDNode *N) { MVT VT = N->getSimpleValueType(0); unsigned NumElts = VT.getVectorNumElements(); APInt DemandedElts = APInt::getZero(NumElts); - for (SDNode *User : N->uses()) { + for (SDNode *User : N->users()) { switch (User->getOpcode()) { case X86ISD::PEXTRB: case X86ISD::PEXTRW: @@ -22143,7 +22143,7 @@ static SDValue LowerFABSorFNEG(SDValue Op, SelectionDAG &DAG) { // If this is a FABS and it has an FNEG user, bail out to fold the combination // into an FNABS. We'll lower the FABS after that if it is still in use. if (IsFABS) - for (SDNode *User : Op->uses()) + for (SDNode *User : Op->users()) if (User->getOpcode() == ISD::FNEG) return Op; @@ -22888,7 +22888,7 @@ static bool hasNonFlagsUse(SDValue Op) { // using an RMW op or only the flags are used. Otherwise, leave // the node alone and emit a 'cmp' or 'test' instruction. static bool isProfitableToUseFlagOp(SDValue Op) { - for (SDNode *U : Op->uses()) + for (SDNode *U : Op->users()) if (U->getOpcode() != ISD::CopyToReg && U->getOpcode() != ISD::SETCC && U->getOpcode() != ISD::STORE) @@ -41712,7 +41712,7 @@ static SDValue combineTargetShuffle(SDValue N, const SDLoc &DL, // Share broadcast with the longest vector and extract low subvector (free). // Ensure the same SDValue from the SDNode use is being used. - for (SDNode *User : Src->uses()) + for (SDNode *User : Src->users()) if (User != N.getNode() && User->getOpcode() == X86ISD::VBROADCAST && Src == User->getOperand(0) && User->getValueSizeInBits(0).getFixedValue() > @@ -42910,7 +42910,7 @@ bool X86TargetLowering::SimplifyDemandedVectorEltsForTargetNode( // If we reuse the shift amount just for sse shift amounts then we know that // only the bottom 64-bits are only ever used. - bool AssumeSingleUse = llvm::all_of(Amt->uses(), [&Amt](SDNode *Use) { + bool AssumeSingleUse = llvm::all_of(Amt->users(), [&Amt](SDNode *Use) { unsigned UseOpc = Use->getOpcode(); return (UseOpc == X86ISD::VSHL || UseOpc == X86ISD::VSRL || UseOpc == X86ISD::VSRA) && @@ -45670,7 +45670,7 @@ combineExtractFromVectorLoad(SDNode *N, EVT VecVT, SDValue SrcVec, uint64_t Idx, const TargetLowering &TLI = DAG.getTargetLoweringInfo(); EVT VT = N->getValueType(0); - bool LikelyUsedAsVector = any_of(N->uses(), [](SDNode *Use) { + bool LikelyUsedAsVector = any_of(N->users(), [](SDNode *Use) { return Use->getOpcode() == ISD::STORE || Use->getOpcode() == ISD::INSERT_VECTOR_ELT || Use->getOpcode() == ISD::SCALAR_TO_VECTOR; @@ -46338,7 +46338,7 @@ static SDValue combineExtractVectorElt(SDNode *N, SelectionDAG &DAG, return false; }; // TODO: Can we drop the oneuse check for constant extracts? - if (all_of(InputVector->uses(), IsBoolExtract) && + if (all_of(InputVector->users(), IsBoolExtract) && (IsVar || BoolExtracts.size() > 1)) { EVT BCVT = EVT::getIntegerVT(*DAG.getContext(), NumSrcElts); if (SDValue BC = @@ -46754,7 +46754,7 @@ static SDValue combineVSelectToBLENDV(SDNode *N, SelectionDAG &DAG, // the generic VSELECT anymore. Otherwise, we may perform wrong // optimizations as we messed with the actual expectation for the vector // boolean values. - for (SDNode *U : Cond->uses()) { + for (SDNode *U : Cond->users()) { if (U->getOpcode() == X86ISD::BLENDV) continue; @@ -49937,7 +49937,7 @@ static SDValue combineCompareEqual(SDNode *N, SelectionDAG &DAG, (VT == MVT::f16 && Subtarget.hasFP16())) { bool ExpectingFlags = false; // Check for any users that want flags: - for (const SDNode *U : N->uses()) { + for (const SDNode *U : N->users()) { if (ExpectingFlags) break; @@ -50765,7 +50765,7 @@ static SDValue combineX86SubCmpForFlags(SDNode *N, SDValue Flag, return SDValue(); // Check the only user of flag is `brcond ne`. - SDNode *BrCond = *Flag->uses().begin(); + SDNode *BrCond = *Flag->use_begin(); if (BrCond->getOpcode() != X86ISD::BRCOND) return SDValue(); unsigned CondNo = 2; @@ -52179,7 +52179,7 @@ static SDValue combineConstantPoolLoads(SDNode *N, const SDLoc &dl, // Look through all other loads/broadcasts in the chain for another constant // pool entry. - for (SDNode *User : Chain->uses()) { + for (SDNode *User : Chain->users()) { auto *UserLd = dyn_cast(User); if (User != N && UserLd && (User->getOpcode() == X86ISD::SUBV_BROADCAST_LOAD || @@ -52289,7 +52289,7 @@ static SDValue combineLoad(SDNode *N, SelectionDAG &DAG, (RegVT.is128BitVector() || RegVT.is256BitVector())) { SDValue Ptr = Ld->getBasePtr(); SDValue Chain = Ld->getChain(); - for (SDNode *User : Chain->uses()) { + for (SDNode *User : Chain->users()) { auto *UserLd = dyn_cast(User); if (User != N && UserLd && User->getOpcode() == X86ISD::SUBV_BROADCAST_LOAD && @@ -53150,8 +53150,8 @@ static bool isHorizontalBinOp(unsigned HOpcode, SDValue &LHS, SDValue &RHS, return User->getOpcode() == HOpcode && User->getValueType(0) == VT; }; ForceHorizOp = - ForceHorizOp || (llvm::any_of(NewLHS->uses(), FoundHorizUser) && - llvm::any_of(NewRHS->uses(), FoundHorizUser)); + ForceHorizOp || (llvm::any_of(NewLHS->users(), FoundHorizUser) && + llvm::any_of(NewRHS->users(), FoundHorizUser)); // Assume a SingleSource HOP if we only shuffle one input and don't need to // shuffle the result. @@ -54878,7 +54878,7 @@ static SDValue promoteExtBeforeAdd(SDNode *Ext, SelectionDAG &DAG, // of single 'add' instructions, but the cost model for selecting an LEA // currently has a high threshold. bool HasLEAPotential = false; - for (auto *User : Ext->uses()) { + for (auto *User : Ext->users()) { if (User->getOpcode() == ISD::ADD || User->getOpcode() == ISD::SHL) { HasLEAPotential = true; break; @@ -55066,10 +55066,11 @@ static SDValue getInvertedVectorForFMA(SDValue V, SelectionDAG &DAG) { // Check if we can eliminate V. We assume if a value is only used in FMAs, we // can eliminate it. Since this function is invoked for each FMA with this // vector. - auto IsNotFMA = [](SDNode *Use) { - return Use->getOpcode() != ISD::FMA && Use->getOpcode() != ISD::STRICT_FMA; + auto IsNotFMA = [](SDNode *User) { + return User->getOpcode() != ISD::FMA && + User->getOpcode() != ISD::STRICT_FMA; }; - if (llvm::any_of(V->uses(), IsNotFMA)) + if (llvm::any_of(V->users(), IsNotFMA)) return SDValue(); SmallVector Ops; @@ -55090,7 +55091,7 @@ static SDValue getInvertedVectorForFMA(SDValue V, SelectionDAG &DAG) { // If an inverted version cannot be eliminated, choose it instead of the // original version. - if (llvm::any_of(NV->uses(), IsNotFMA)) + if (llvm::any_of(NV->users(), IsNotFMA)) return SDValue(NV, 0); // If the inverted version also can be eliminated, we have to consistently @@ -56183,7 +56184,7 @@ static SDValue combineSIntToFP(SDNode *N, SelectionDAG &DAG, static bool needCarryOrOverflowFlag(SDValue Flags) { assert(Flags.getValueType() == MVT::i32 && "Unexpected VT!"); - for (const SDNode *User : Flags->uses()) { + for (const SDNode *User : Flags->users()) { X86::CondCode CC; switch (User->getOpcode()) { default: @@ -56218,7 +56219,7 @@ static bool needCarryOrOverflowFlag(SDValue Flags) { static bool onlyZeroFlagUsed(SDValue Flags) { assert(Flags.getValueType() == MVT::i32 && "Unexpected VT!"); - for (const SDNode *User : Flags->uses()) { + for (const SDNode *User : Flags->users()) { unsigned CCOpNo; switch (User->getOpcode()) { default: @@ -56829,7 +56830,7 @@ static SDValue pushAddIntoCmovOfConsts(SDNode *N, const SDLoc &DL, // TODO: If target has "slow3OpsLEA", do this even without the trailing memop? if (OtherOp.getOpcode() == ISD::ADD && OtherOp.hasOneUse() && !isa(OtherOp.getOperand(0)) && - all_of(N->uses(), [&](SDNode *Use) { + all_of(N->users(), [&](SDNode *Use) { auto *MemNode = dyn_cast(Use); return MemNode && MemNode->getBasePtr().getNode() == N; })) { @@ -58485,7 +58486,7 @@ static SDValue combineScalarToVector(SDNode *N, SelectionDAG &DAG, // See if we're broadcasting the scalar value, in which case just reuse that. // Ensure the same SDValue from the SDNode use is being used. if (VT.getScalarType() == Src.getValueType()) - for (SDNode *User : Src->uses()) + for (SDNode *User : Src->users()) if (User->getOpcode() == X86ISD::VBROADCAST && Src == User->getOperand(0)) { unsigned SizeInBits = VT.getFixedSizeInBits(); @@ -58881,7 +58882,7 @@ static SDValue combineBROADCAST_LOAD(SDNode *N, SelectionDAG &DAG, // Look at other users of our base pointer and try to find a wider broadcast. // The input chain and the size of the memory VT must match. - for (SDNode *User : Ptr->uses()) + for (SDNode *User : Ptr->users()) if (User != N && User->getOpcode() == N->getOpcode() && cast(User)->getBasePtr() == Ptr && cast(User)->getChain() == Chain && diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp index 05a5a36ce5cbe..df12ea2f79df5 100644 --- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp +++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp @@ -955,7 +955,7 @@ bool X86TargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { return false; bool HasRet = false; - for (const SDNode *U : Copy->uses()) { + for (const SDNode *U : Copy->users()) { if (U->getOpcode() != X86ISD::RET_GLUE) return false; // If we are returning more than one value, we can definitely From 2302142f2318ba9624b847cd8c1a7e2d255be5c5 Mon Sep 17 00:00:00 2001 From: Tyler Nowicki Date: Wed, 18 Dec 2024 23:47:00 -0500 Subject: [PATCH 008/209] [Coroutines][Docs] Add a discussion on the handling of certain parameter attribs (#117183) ByVal arguments and Swifterror require special handling in the coroutine passes. The goal of this section is to provide a description of how these parameter attributes are handled. --- llvm/docs/Coroutines.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst index 92e138b6893b2..60e32dc467d27 100644 --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -810,6 +810,28 @@ The LLVM IR for a coroutine using a Coroutine with a custom ABI looks like: ret ptr %hdl } +Parameter Attributes +==================== +Some parameter attributes, used to communicate additional information about the result or parameters of a function, require special handling. + +ByVal +----- +A ByVal parameter on an argument indicates that the pointee should be treated as being passed by value to the function. +Prior to the coroutine transforms loads and stores to/from the pointer are generated where the value is needed. +Consequently, a ByVal argument is treated much like an alloca. +Space is allocated for it on the coroutine frame and the uses of the argument pointer are replaced with a pointer to the coroutine frame. + +Swift Error +----------- +Clang supports the swiftcall calling convention in many common targets, and a user could call a function that takes a swifterror argument from a C++ coroutine. +The swifterror parameter attribute exists to model and optimize Swift error handling. +A swifterror alloca or parameter can only be loaded, stored, or passed as a swifterror call argument, and a swifterror call argument can only be a direct reference to a swifterror alloca or parameter. +These rules, not coincidentally, mean that you can always perfectly model the data flow in the alloca, and LLVM CodeGen actually has to do that in order to emit code. + +For coroutine lowering the default treatment of allocas breaks those rules — splitting will try to replace the alloca with an entry in the coro frame, which can lead to trying to pass that as a swifterror argument. +To pass a swifterror argument in a split function, we need to still have the alloca around; but we also potentially need the coro frame slot, since useful data can (in theory) be stored in the swifterror alloca slot across suspensions in the presplit coroutine. +When split a coroutine it is consequently necessary to keep both the frame slot as well as the alloca itself and then keep them in sync. + Intrinsics ========== From 2c782ab2718758bd106ad5939adf7cfb6cd9d1e9 Mon Sep 17 00:00:00 2001 From: Pengcheng Wang Date: Thu, 19 Dec 2024 13:00:08 +0800 Subject: [PATCH 009/209] [RISCV] Add software pipeliner support (#117546) This patch adds basic support of `MachinePipeliner` and disable it by default. The functionality should be OK and all llvm-test-suite tests have passed. --- llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 81 ++++++++++++++ llvm/lib/Target/RISCV/RISCVInstrInfo.h | 3 + llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 4 + llvm/lib/Target/RISCV/RISCVSubtarget.h | 4 + llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 8 ++ llvm/test/CodeGen/RISCV/machine-pipeliner.ll | 109 +++++++++++++++++++ 6 files changed, 209 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/machine-pipeliner.ll diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 7e0063589b6f4..0af8161a307ab 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -4248,3 +4248,84 @@ bool RISCV::isVLKnownLE(const MachineOperand &LHS, const MachineOperand &RHS) { return false; return LHS.getImm() <= RHS.getImm(); } + +namespace { +class RISCVPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo { + const MachineInstr *LHS; + const MachineInstr *RHS; + SmallVector Cond; + +public: + RISCVPipelinerLoopInfo(const MachineInstr *LHS, const MachineInstr *RHS, + const SmallVectorImpl &Cond) + : LHS(LHS), RHS(RHS), Cond(Cond.begin(), Cond.end()) {} + + bool shouldIgnoreForPipelining(const MachineInstr *MI) const override { + // Make the instructions for loop control be placed in stage 0. + // The predecessors of LHS/RHS are considered by the caller. + if (LHS && MI == LHS) + return true; + if (RHS && MI == RHS) + return true; + return false; + } + + std::optional createTripCountGreaterCondition( + int TC, MachineBasicBlock &MBB, + SmallVectorImpl &CondParam) override { + // A branch instruction will be inserted as "if (Cond) goto epilogue". + // Cond is normalized for such use. + // The predecessors of the branch are assumed to have already been inserted. + CondParam = Cond; + return {}; + } + + void setPreheader(MachineBasicBlock *NewPreheader) override {} + + void adjustTripCount(int TripCountAdjust) override {} + + void disposed() override {} +}; +} // namespace + +std::unique_ptr +RISCVInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { + MachineBasicBlock *TBB = nullptr, *FBB = nullptr; + SmallVector Cond; + if (analyzeBranch(*LoopBB, TBB, FBB, Cond, /*AllowModify=*/false)) + return nullptr; + + // Infinite loops are not supported + if (TBB == LoopBB && FBB == LoopBB) + return nullptr; + + // Must be conditional branch + if (FBB == nullptr) + return nullptr; + + assert((TBB == LoopBB || FBB == LoopBB) && + "The Loop must be a single-basic-block loop"); + + // Normalization for createTripCountGreaterCondition() + if (TBB == LoopBB) + reverseBranchCondition(Cond); + + const MachineRegisterInfo &MRI = LoopBB->getParent()->getRegInfo(); + auto FindRegDef = [&MRI](MachineOperand &Op) -> const MachineInstr * { + if (!Op.isReg()) + return nullptr; + Register Reg = Op.getReg(); + if (!Reg.isVirtual()) + return nullptr; + return MRI.getVRegDef(Reg); + }; + + const MachineInstr *LHS = FindRegDef(Cond[1]); + const MachineInstr *RHS = FindRegDef(Cond[2]); + if (LHS && LHS->isPHI()) + return nullptr; + if (RHS && RHS->isPHI()) + return nullptr; + + return std::make_unique(LHS, RHS, Cond); +} diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h index 005cba5d35610..7e8bcd451a8ef 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h @@ -298,6 +298,9 @@ class RISCVInstrInfo : public RISCVGenInstrInfo { unsigned getTailDuplicateSize(CodeGenOptLevel OptLevel) const override; + std::unique_ptr + analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; + protected: const RISCVSubtarget &STI; diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp index 90131d82534b1..6e212dc58e6dd 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -194,6 +194,10 @@ bool RISCVSubtarget::useRVVForFixedLengthVectors() const { bool RISCVSubtarget::enableSubRegLiveness() const { return true; } +bool RISCVSubtarget::enableMachinePipeliner() const { + return getSchedModel().hasInstrSchedModel(); +} + /// Enable use of alias analysis during code generation (during MI /// scheduling, DAGCombine, etc.). bool RISCVSubtarget::useAA() const { return UseAA; } diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h index 096d696c71f8f..87d508c394173 100644 --- a/llvm/lib/Target/RISCV/RISCVSubtarget.h +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -324,6 +324,10 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo { bool enableSubRegLiveness() const override; + bool enableMachinePipeliner() const override; + + bool useDFAforSMS() const override { return false; } + bool useAA() const override; unsigned getCacheLineSize() const override { diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index 0b8407943a907..f6ccbfbe217df 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -112,6 +112,11 @@ static cl::opt DisableVectorMaskMutation( cl::desc("Disable the vector mask scheduling mutation"), cl::init(false), cl::Hidden); +static cl::opt + EnableMachinePipeliner("riscv-enable-pipeliner", + cl::desc("Enable Machine Pipeliner for RISC-V"), + cl::init(false), cl::Hidden); + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() { RegisterTargetMachine X(getTheRISCV32Target()); RegisterTargetMachine Y(getTheRISCV64Target()); @@ -603,6 +608,9 @@ void RISCVPassConfig::addPreRegAlloc() { addPass(createRISCVInsertReadWriteCSRPass()); addPass(createRISCVInsertWriteVXRMPass()); addPass(createRISCVLandingPadSetupPass()); + + if (TM->getOptLevel() != CodeGenOptLevel::None && EnableMachinePipeliner) + addPass(&MachinePipelinerID); } void RISCVPassConfig::addFastRegAlloc() { diff --git a/llvm/test/CodeGen/RISCV/machine-pipeliner.ll b/llvm/test/CodeGen/RISCV/machine-pipeliner.ll new file mode 100644 index 0000000000000..d250098576687 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/machine-pipeliner.ll @@ -0,0 +1,109 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=riscv64 -mcpu=sifive-p670 -O3 -verify-machineinstrs -riscv-enable-pipeliner=false < %s \ +; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NOT-PIPELINED +; RUN: llc -mtriple=riscv64 -mcpu=sifive-p670 -O3 -verify-machineinstrs -riscv-enable-pipeliner=true < %s \ +; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PIPELINED + +; We shouldn't pipeline this loop as one operand of branch is a PHI. +define i32 @test_phi() { +; CHECK-LABEL: test_phi: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: .LBB0_1: # %for.body +; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: mv a1, a0 +; CHECK-NEXT: li a0, 1 +; CHECK-NEXT: sh a0, 0(zero) +; CHECK-NEXT: bnez a1, .LBB0_1 +; CHECK-NEXT: # %bb.2: # %for.cond.cleanup +; CHECK-NEXT: li a0, 0 +; CHECK-NEXT: ret +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.body + ret i32 0 + +for.body: ; preds = %for.body, %entry + %indvars.iv1 = phi i64 [ 0, %entry ], [ 1, %for.body ] + store i16 1, ptr null, align 4 + %exitcond.not.31 = icmp eq i64 %indvars.iv1, 0 + br i1 %exitcond.not.31, label %for.cond.cleanup, label %for.body +} + +define void @test_pipelined_1(ptr noalias %in, ptr noalias %out, i32 signext %cnt) { +; CHECK-NOT-PIPELINED-LABEL: test_pipelined_1: +; CHECK-NOT-PIPELINED: # %bb.0: # %entry +; CHECK-NOT-PIPELINED-NEXT: blez a2, .LBB1_3 +; CHECK-NOT-PIPELINED-NEXT: # %bb.1: # %for.body.preheader +; CHECK-NOT-PIPELINED-NEXT: addi a2, a2, -1 +; CHECK-NOT-PIPELINED-NEXT: sh2add.uw a2, a2, a1 +; CHECK-NOT-PIPELINED-NEXT: addi a2, a2, 4 +; CHECK-NOT-PIPELINED-NEXT: .LBB1_2: # %for.body +; CHECK-NOT-PIPELINED-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NOT-PIPELINED-NEXT: lw a3, 0(a1) +; CHECK-NOT-PIPELINED-NEXT: addi a1, a1, 4 +; CHECK-NOT-PIPELINED-NEXT: addi a3, a3, 1 +; CHECK-NOT-PIPELINED-NEXT: sw a3, 0(a0) +; CHECK-NOT-PIPELINED-NEXT: addi a0, a0, 4 +; CHECK-NOT-PIPELINED-NEXT: bne a1, a2, .LBB1_2 +; CHECK-NOT-PIPELINED-NEXT: .LBB1_3: # %for.end +; CHECK-NOT-PIPELINED-NEXT: ret +; +; CHECK-PIPELINED-LABEL: test_pipelined_1: +; CHECK-PIPELINED: # %bb.0: # %entry +; CHECK-PIPELINED-NEXT: blez a2, .LBB1_6 +; CHECK-PIPELINED-NEXT: # %bb.1: # %for.body.preheader +; CHECK-PIPELINED-NEXT: lw a4, 0(a1) +; CHECK-PIPELINED-NEXT: addi a2, a2, -1 +; CHECK-PIPELINED-NEXT: sh2add.uw a6, a2, a1 +; CHECK-PIPELINED-NEXT: addi a2, a0, 4 +; CHECK-PIPELINED-NEXT: addi a1, a1, 4 +; CHECK-PIPELINED-NEXT: addi a6, a6, 4 +; CHECK-PIPELINED-NEXT: beq a1, a6, .LBB1_5 +; CHECK-PIPELINED-NEXT: # %bb.2: # %for.body +; CHECK-PIPELINED-NEXT: lw a5, 0(a1) +; CHECK-PIPELINED-NEXT: addi a3, a2, 4 +; CHECK-PIPELINED-NEXT: addi a4, a4, 1 +; CHECK-PIPELINED-NEXT: addi a1, a1, 4 +; CHECK-PIPELINED-NEXT: beq a1, a6, .LBB1_4 +; CHECK-PIPELINED-NEXT: .LBB1_3: # %for.body +; CHECK-PIPELINED-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-PIPELINED-NEXT: sw a4, 0(a0) +; CHECK-PIPELINED-NEXT: mv a4, a5 +; CHECK-PIPELINED-NEXT: lw a5, 0(a1) +; CHECK-PIPELINED-NEXT: mv a0, a2 +; CHECK-PIPELINED-NEXT: mv a2, a3 +; CHECK-PIPELINED-NEXT: addi a3, a3, 4 +; CHECK-PIPELINED-NEXT: addi a4, a4, 1 +; CHECK-PIPELINED-NEXT: addi a1, a1, 4 +; CHECK-PIPELINED-NEXT: bne a1, a6, .LBB1_3 +; CHECK-PIPELINED-NEXT: .LBB1_4: +; CHECK-PIPELINED-NEXT: sw a4, 0(a0) +; CHECK-PIPELINED-NEXT: mv a0, a2 +; CHECK-PIPELINED-NEXT: mv a4, a5 +; CHECK-PIPELINED-NEXT: .LBB1_5: +; CHECK-PIPELINED-NEXT: addi a4, a4, 1 +; CHECK-PIPELINED-NEXT: sw a4, 0(a0) +; CHECK-PIPELINED-NEXT: .LBB1_6: # %for.end +; CHECK-PIPELINED-NEXT: ret +entry: + %cmp = icmp sgt i32 %cnt, 0 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %entry, %for.body + %inc.next = phi i32 [ %inc, %for.body ], [ 0, %entry ] + %in.addr.next = phi ptr [ %incdec.in, %for.body ], [ %in, %entry ] + %out.addr.next = phi ptr [ %incdec.out, %for.body ], [ %out, %entry ] + %0 = load i32, ptr %out.addr.next, align 4 + %1 = add i32 %0, 1 + store i32 %1, ptr %in.addr.next, align 4 + %incdec.in = getelementptr inbounds i8, ptr %in.addr.next, i64 4 + %incdec.out = getelementptr inbounds i8, ptr %out.addr.next, i64 4 + %inc = add nuw nsw i32 %inc.next, 1 + %exitcond.not = icmp eq i32 %inc, %cnt + br i1 %exitcond.not, label %for.end, label %for.body + +for.end: ; preds = %for.body, %entry + ret void +} From 5c55f9664f7e2f9fe29589a97bc5818d6b8d3c9c Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Thu, 19 Dec 2024 13:12:01 +0800 Subject: [PATCH 010/209] [Clang] Don't assume unexpanded PackExpansions' size when expanding packs (#120380) CheckParameterPacksForExpansion() previously assumed that template arguments don't include PackExpansion types when attempting another pack expansion (i.e. when NumExpansions is present). However, this assumption doesn't hold for type aliases, whose substitution might involve unexpanded packs. This can lead to incorrect diagnostics during substitution because the pack size is not yet determined. To address this, this patch calculates the minimum pack size (ignoring unexpanded PackExpansionTypes) and compares it to the previously expanded size. If the minimum pack size is smaller, then there's still a chance for future substitution to expand it to a correct size, so we don't diagnose it too eagerly. Fixes #61415 Fixes #32252 Fixes #17042 --- clang/docs/ReleaseNotes.rst | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaTemplateVariadic.cpp | 57 ++++++++++++++++-- clang/test/SemaTemplate/pack-deduction.cpp | 59 +++++++++++++++++++ 4 files changed, 113 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 29794f27d3005..5f91ff9063403 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -850,6 +850,7 @@ Bug Fixes to C++ Support - Clang no longer rejects deleting a pointer of incomplete enumeration type. (#GH99278) - Fixed recognition of ``std::initializer_list`` when it's surrounded with ``extern "C++"`` and exported out of a module (which is the case e.g. in MSVC's implementation of ``std`` module). (#GH118218) +- Fixed a pack expansion issue in checking unexpanded parameter sizes. (#GH17042) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d67a81f8564a8..7bd154e7da2f4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5863,10 +5863,10 @@ def err_pack_expansion_without_parameter_packs : Error< "pack expansion does not contain any unexpanded parameter packs">; def err_pack_expansion_length_conflict : Error< "pack expansion contains parameter packs %0 and %1 that have different " - "lengths (%2 vs. %3)">; + "lengths (%2 vs. %select{|at least }3%4))">; def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " - "length (%1 vs. %2) from outer parameter packs">; + "length (%1 vs. %select{|at least }2%3) from outer parameter packs">; def err_pack_expansion_length_conflict_partial : Error< "pack expansion contains parameter pack %0 that has a different " "length (at least %1 vs. %2) from outer parameter packs">; diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 88a21240e1c80..c8452db6bc901 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -780,7 +780,7 @@ bool Sema::CheckParameterPacksForExpansion( } // Determine the size of this argument pack. - unsigned NewPackSize; + unsigned NewPackSize, PendingPackExpansionSize = 0; if (IsVarDeclPack) { // Figure out whether we're instantiating to an argument pack or not. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; @@ -808,7 +808,25 @@ bool Sema::CheckParameterPacksForExpansion( } // Determine the size of the argument pack. - NewPackSize = TemplateArgs(Depth, Index).pack_size(); + ArrayRef Pack = + TemplateArgs(Depth, Index).getPackAsArray(); + NewPackSize = Pack.size(); + PendingPackExpansionSize = + llvm::count_if(Pack, [](const TemplateArgument &TA) { + if (!TA.isPackExpansion()) + return false; + + if (TA.getKind() == TemplateArgument::Type) + return !TA.getAsType() + ->getAs() + ->getNumExpansions(); + + if (TA.getKind() == TemplateArgument::Expression) + return !cast(TA.getAsExpr()) + ->getNumExpansions(); + + return !TA.getNumTemplateExpansions(); + }); } // C++0x [temp.arg.explicit]p9: @@ -831,7 +849,7 @@ bool Sema::CheckParameterPacksForExpansion( } if (!NumExpansions) { - // The is the first pack we've seen for which we have an argument. + // This is the first pack we've seen for which we have an argument. // Record it. NumExpansions = NewPackSize; FirstPack.first = Name; @@ -841,17 +859,44 @@ bool Sema::CheckParameterPacksForExpansion( } if (NewPackSize != *NumExpansions) { + // In some cases, we might be handling packs with unexpanded template + // arguments. For example, this can occur when substituting into a type + // alias declaration that uses its injected template parameters as + // arguments: + // + // template struct S { + // template using Alias = S; + // }; + // + // Consider an instantiation attempt like 'S::Alias', where + // Pack comes from another template parameter. 'S' is first + // instantiated, expanding the outer pack 'Outer' to . The alias + // declaration is accordingly substituted, leaving the template arguments + // as unexpanded + // ''. + // + // Since we have no idea of the size of '' until its expansion, + // we shouldn't assume its pack size for validation. However if we are + // certain that there are extra arguments beyond unexpanded packs, in + // which case the pack size is already larger than the previous expansion, + // we can complain that before instantiation. + unsigned LeastNewPackSize = NewPackSize - PendingPackExpansionSize; + if (PendingPackExpansionSize && LeastNewPackSize <= *NumExpansions) { + ShouldExpand = false; + continue; + } // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. if (HaveFirstPack) Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *NumExpansions << NewPackSize + << FirstPack.first << Name << *NumExpansions + << (LeastNewPackSize != NewPackSize) << LeastNewPackSize << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); else Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << Name << *NumExpansions << NewPackSize - << SourceRange(ParmPack.second); + << Name << *NumExpansions << (LeastNewPackSize != NewPackSize) + << LeastNewPackSize << SourceRange(ParmPack.second); return true; } } diff --git a/clang/test/SemaTemplate/pack-deduction.cpp b/clang/test/SemaTemplate/pack-deduction.cpp index 28fb127a38644..b3104609994a4 100644 --- a/clang/test/SemaTemplate/pack-deduction.cpp +++ b/clang/test/SemaTemplate/pack-deduction.cpp @@ -199,3 +199,62 @@ constexpr auto baz(Int(T())>... x) -> int { return 1; } static_assert(baz, Int<2>, Int<3>>(Int<10>(), Int<10>(), Int<10>()) == 1, ""); } + +namespace GH17042 { + +template struct X { + template using Y = X; // #GH17042_Y +}; + +template +using any_pairs_list = X::Y; // #any_pairs_list + +template +using any_pairs_list_2 = X::Y<>; +// expected-error@#GH17042_Y {{different length (2 vs. 0)}} \ +// expected-note@-1 {{requested here}} + +template +using any_pairs_list_3 = X::Y; // #any_pairs_list_3 + +template +using any_pairs_list_4 = X::Y; +// expected-error@#GH17042_Y {{different length (2 vs. at least 3)}} \ +// expected-note@-1 {{requested here}} + +static_assert(__is_same(any_pairs_list, X), ""); + +static_assert(!__is_same(any_pairs_list, X), ""); +// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-note@#any_pairs_list {{requested here}} \ +// expected-note@-1 {{requested here}} + +static_assert(__is_same(any_pairs_list_3, X), ""); + +static_assert(!__is_same(any_pairs_list_3, X), ""); +// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-note@#any_pairs_list_3 {{requested here}} \ +// expected-note@-1 {{requested here}} + +namespace TemplateTemplateParameters { +template struct C {}; + +template class... Args1> struct Ttp { + template