https://github.com/bviyer updated https://github.com/llvm/llvm-project/pull/172399
>From 18a648b9b1a5afb20ac964f581f80281377360e1 Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer" <[email protected]> Date: Mon, 15 Dec 2025 20:36:00 -0600 Subject: [PATCH 1/6] Check for a valid Index in array before getting it Fixes https://github.com/llvm/llvm-project/issues/154713 --- clang/lib/AST/ExprConstant.cpp | 4 ++++ clang/test/AST/array-overflow-index.c | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 clang/test/AST/array-overflow-index.c diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 11c5e1c6e90f4..fb85119b137ab 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9749,6 +9749,10 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (Success) { Result.setFrom(Info.Ctx, Val); + // If Index cannot be represented as a 64 bit integer, return unsuccessful. + if (!Index.tryExtValue().has_value()) + return Error(E); + HandleLValueVectorElement(Info, E, Result, VT->getElementType(), VT->getNumElements(), Index.getExtValue()); } diff --git a/clang/test/AST/array-overflow-index.c b/clang/test/AST/array-overflow-index.c new file mode 100644 index 0000000000000..8a43cfbb01f91 --- /dev/null +++ b/clang/test/AST/array-overflow-index.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -verify %s + +// ref-no-diagnostics +// expected-no-diagnostics + +int __attribute__((vector_size(4))) test_vector = {1}; +int get_last_element(void) { + return test_vector[~0UL]; +} >From 841213bf09f2e3779ad5d2f32af880c80a26e21a Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer" <[email protected]> Date: Mon, 15 Dec 2025 21:15:59 -0600 Subject: [PATCH 2/6] Added Linting --- clang/lib/AST/ExprConstant.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fb85119b137ab..4057183ae21c9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9749,7 +9749,8 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (Success) { Result.setFrom(Info.Ctx, Val); - // If Index cannot be represented as a 64 bit integer, return unsuccessful. + // If Index cannot be represented as a 64 bit integer, return + // unsuccessful. if (!Index.tryExtValue().has_value()) return Error(E); >From f6ca4dabbab5ae1fdf8047a131a8d31335211568 Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer." <[email protected]> Date: Tue, 16 Dec 2025 13:41:06 -0600 Subject: [PATCH 3/6] Update clang/test/AST/array-overflow-index.c Co-authored-by: Mariya Podchishchaeva <[email protected]> --- clang/test/AST/array-overflow-index.c | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/test/AST/array-overflow-index.c b/clang/test/AST/array-overflow-index.c index 8a43cfbb01f91..99bd2b9318017 100644 --- a/clang/test/AST/array-overflow-index.c +++ b/clang/test/AST/array-overflow-index.c @@ -1,6 +1,5 @@ // RUN: %clang_cc1 -verify %s -// ref-no-diagnostics // expected-no-diagnostics int __attribute__((vector_size(4))) test_vector = {1}; >From af050c97623b5d08d12f1e9de5ce107f88adb9fc Mon Sep 17 00:00:00 2001 From: Nishant Patel <[email protected]> Date: Wed, 3 Dec 2025 13:38:17 -0800 Subject: [PATCH 4/6] [MLIR][Vector] Add unroll pattern for vector.create_mask (#169119) This PR adds unrolling for vector.create_mask op based on the targetShape. Each unrolled vector computes its local mask size in each dimension (d) as: min(max(originalMaskSize[d] - offset[d], 0), unrolledMaskSize[d]). --- .../mlir/Dialect/Vector/IR/VectorOps.td | 4 +- .../Vector/Transforms/VectorUnroll.cpp | 96 ++++++++++++++++++- .../Dialect/Vector/vector-unroll-options.mlir | 55 +++++++++++ .../Dialect/Vector/TestVectorTransforms.cpp | 6 ++ 4 files changed, 158 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td index 43ebcaa03a470..d8ed46c2820fe 100644 --- a/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td +++ b/mlir/include/mlir/Dialect/Vector/IR/VectorOps.td @@ -2605,7 +2605,9 @@ def Vector_ConstantMaskOp : } def Vector_CreateMaskOp : - Vector_Op<"create_mask", [Pure]>, + Vector_Op<"create_mask", [Pure, + DeclareOpInterfaceMethods<VectorUnrollOpInterface> + ]>, Arguments<(ins Variadic<Index>:$operands)>, Results<(outs VectorOfAnyRankOf<[I1]>)> { let summary = "creates a vector mask"; diff --git a/mlir/lib/Dialect/Vector/Transforms/VectorUnroll.cpp b/mlir/lib/Dialect/Vector/Transforms/VectorUnroll.cpp index b60f80534bfb6..462bd8c3dc4a6 100644 --- a/mlir/lib/Dialect/Vector/Transforms/VectorUnroll.cpp +++ b/mlir/lib/Dialect/Vector/Transforms/VectorUnroll.cpp @@ -1003,6 +1003,97 @@ struct UnrollFromElements : OpRewritePattern<vector::FromElementsOp> { vector::UnrollVectorOptions options; }; +/// This pattern unrolls `vector.create_mask` operations into smaller mask +/// operations based on the target unroll shape. Each unrolled slice computes +/// its local mask size in each dimension (d) as: +/// min(max(originalMaskSize[d] - offset[d], 0), unrolledDimSize[d]). +/// Example: +/// Given a create_mask operation: +/// %0 = vector.create_mask %c6, %c10 : vector<8x16xi1> // mask first 6x10 +/// elements +/// +/// and a target unroll shape of <4x8>, the pattern produces: +/// +/// %false = arith.constant dense<false> : vector<8x16xi1> +/// +/// Slice [0,0]: +/// mask size = min(max(6-0, 0), 4) x min(max(10-0, 0), 8) = 4x8 +/// %mask00 = vector.create_mask %c4, %c8 : vector<4x8xi1> +/// %r0 = vector.insert_strided_slice %mask00, %false [0, 0], [1, 1] +/// : vector<4x8xi1> into vector<8x16xi1> +/// Slice [0,8]: +/// mask size = min(max(6-0, 0), 4) x min(max(10-8, 0), 8) = 4x2 +/// %mask01 = vector.create_mask %c4, %c2 : vector<4x8xi1> +/// %r1 = vector.insert_strided_slice %mask01, %r0 [0, 8], [1, 1] +/// : vector<4x8xi1> into vector<8x16xi1> +/// Slice [4,0]: +/// mask size = min(max(6-4, 0), 4) x min(max(10-0, 0), 8) = 2x8 +/// %mask10 = vector.create_mask %c2, %c8 : vector<4x8xi1> +/// %r2 = vector.insert_strided_slice %mask10, %r1 [4, 0], [1, 1] +/// : vector<4x8xi1> into vector<8x16xi1> +/// Slice [4,8]: +/// mask size = min(max(6-4, 0), 4) x min(max(10-8, 0), 8) = 2x2 +/// %mask11 = vector.create_mask %c2, %c2 : vector<4x8xi1> +/// %result = vector.insert_strided_slice %mask11, %r2 [4, 8], [1, 1] +/// : vector<4x8xi1> into vector<8x16xi1> +struct UnrollCreateMaskPattern : public OpRewritePattern<vector::CreateMaskOp> { + UnrollCreateMaskPattern(MLIRContext *context, + const vector::UnrollVectorOptions &options, + PatternBenefit benefit = 1) + : OpRewritePattern<vector::CreateMaskOp>(context, benefit), + options(options) {} + + LogicalResult matchAndRewrite(vector::CreateMaskOp createMaskOp, + PatternRewriter &rewriter) const override { + auto targetShape = getTargetShape(options, createMaskOp); + if (!targetShape) + return failure(); + + VectorType resultType = createMaskOp.getVectorType(); + SmallVector<int64_t> originalSize = *createMaskOp.getShapeForUnroll(); + Location loc = createMaskOp.getLoc(); + + Value result = arith::ConstantOp::create(rewriter, loc, resultType, + rewriter.getZeroAttr(resultType)); + VectorType targetVectorType = + VectorType::get(*targetShape, rewriter.getI1Type()); + SmallVector<int64_t> strides(targetShape->size(), 1); + + // In each dimension (d), each unrolled vector computes its mask size as: + // min(max(originalMaskOperands[d] - offset[d], 0), unrolledDimSize[d]). + for (SmallVector<int64_t> offsets : + StaticTileOffsetRange(originalSize, *targetShape)) { + SmallVector<Value> unrolledOperands; + + for (auto [i, originalMaskOperand] : + llvm::enumerate(createMaskOp.getOperands())) { + Value offsetVal = + arith::ConstantIndexOp::create(rewriter, loc, offsets[i]); + Value adjustedMaskSize = rewriter.createOrFold<arith::SubIOp>( + loc, originalMaskOperand, offsetVal); + Value zero = arith::ConstantIndexOp::create(rewriter, loc, 0); + Value unrolledDimSize = + arith::ConstantIndexOp::create(rewriter, loc, (*targetShape)[i]); + Value nonNegative = + rewriter.createOrFold<arith::MaxSIOp>(loc, adjustedMaskSize, zero); + Value unrolledOperand = rewriter.createOrFold<arith::MinSIOp>( + loc, nonNegative, unrolledDimSize); + unrolledOperands.push_back(unrolledOperand); + } + + auto unrolledMask = rewriter.createOrFold<vector::CreateMaskOp>( + loc, targetVectorType, unrolledOperands); + result = rewriter.createOrFold<vector::InsertStridedSliceOp>( + loc, unrolledMask, result, offsets, strides); + } + rewriter.replaceOp(createMaskOp, result); + return success(); + } + +private: + vector::UnrollVectorOptions options; +}; + /// Checks whether extractShape is a contiguous slice of shape. /// For extractShape to be contiguous in shape: /// 1) All but the leading dimension of extractShape and shape must match @@ -1202,8 +1293,9 @@ void mlir::vector::populateVectorUnrollPatterns( UnrollReductionPattern, UnrollMultiReductionPattern, UnrollTransposePattern, UnrollGatherPattern, UnrollLoadPattern, UnrollStorePattern, UnrollBroadcastPattern, UnrollFromElements, - UnrollToElements, UnrollStepPattern, UnrollShapeCastPattern>( - patterns.getContext(), options, benefit); + UnrollToElements, UnrollStepPattern, UnrollShapeCastPattern, + UnrollCreateMaskPattern>(patterns.getContext(), options, + benefit); } void mlir::vector::populateVectorToElementsUnrollPatterns( diff --git a/mlir/test/Dialect/Vector/vector-unroll-options.mlir b/mlir/test/Dialect/Vector/vector-unroll-options.mlir index dec32e1c61a9b..805e66f133c59 100644 --- a/mlir/test/Dialect/Vector/vector-unroll-options.mlir +++ b/mlir/test/Dialect/Vector/vector-unroll-options.mlir @@ -497,6 +497,61 @@ func.func @elementwise_4D_to_2D(%v1: vector<2x2x2x2xf32>, %v2: vector<2x2x2x2xf3 // CHECK-NOT: arith.addf // CHECK: return +func.func @vector_create_mask(%size1: index, %size2: index) -> vector<16x16xi1> { + %0 = vector.create_mask %size1, %size2 : vector<16x16xi1> + return %0 : vector<16x16xi1> +} + +// CHECK-LABEL: func @vector_create_mask +// CHECK-SAME: (%[[ARG0:.*]]: index, %[[ARG1:.*]]: index) -> vector<16x16xi1> +// CHECK: %[[CST:.*]] = arith.constant dense<false> : vector<16x16xi1> +// CHECK: %[[C0:.*]] = arith.constant 0 : index +// CHECK: %[[C8:.*]] = arith.constant 8 : index +// CHECK: %[[MAX0:.*]] = arith.maxsi %[[ARG0]], %[[C0]] : index +// CHECK: %[[MIN0:.*]] = arith.minsi %[[MAX0]], %[[C8]] : index +// CHECK: %[[MAX1:.*]] = arith.maxsi %[[ARG1]], %[[C0]] : index +// CHECK: %[[MIN1:.*]] = arith.minsi %[[MAX1]], %[[C8]] : index +// CHECK: %[[MASK00:.*]] = vector.create_mask %[[MIN0]], %[[MIN1]] : vector<8x8xi1> +// CHECK: %[[INS00:.*]] = vector.insert_strided_slice %[[MASK00]], %[[CST]] {offsets = [0, 0], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[MAX0_2:.*]] = arith.maxsi %[[ARG0]], %[[C0]] : index +// CHECK: %[[MIN0_2:.*]] = arith.minsi %[[MAX0_2]], %[[C8]] : index +// CHECK: %[[SUB1:.*]] = arith.subi %[[ARG1]], %[[C8]] : index +// CHECK: %[[MAX1_2:.*]] = arith.maxsi %[[SUB1]], %[[C0]] : index +// CHECK: %[[MIN1_2:.*]] = arith.minsi %[[MAX1_2]], %[[C8]] : index +// CHECK: %[[MASK01:.*]] = vector.create_mask %[[MIN0_2]], %[[MIN1_2]] : vector<8x8xi1> +// CHECK: %[[INS01:.*]] = vector.insert_strided_slice %[[MASK01]], %[[INS00]] {offsets = [0, 8], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[SUB0:.*]] = arith.subi %[[ARG0]], %[[C8]] : index +// CHECK: %[[MAX0_3:.*]] = arith.maxsi %[[SUB0]], %[[C0]] : index +// CHECK: %[[MIN0_3:.*]] = arith.minsi %[[MAX0_3]], %[[C8]] : index +// CHECK: %[[MAX1_3:.*]] = arith.maxsi %[[ARG1]], %[[C0]] : index +// CHECK: %[[MIN1_3:.*]] = arith.minsi %[[MAX1_3]], %[[C8]] : index +// CHECK: %[[MASK10:.*]] = vector.create_mask %[[MIN0_3]], %[[MIN1_3]] : vector<8x8xi1> +// CHECK: %[[INS10:.*]] = vector.insert_strided_slice %[[MASK10]], %[[INS01]] {offsets = [8, 0], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[SUB0_2:.*]] = arith.subi %[[ARG0]], %[[C8]] : index +// CHECK: %[[MAX0_4:.*]] = arith.maxsi %[[SUB0_2]], %[[C0]] : index +// CHECK: %[[MIN0_4:.*]] = arith.minsi %[[MAX0_4]], %[[C8]] : index +// CHECK: %[[SUB1_2:.*]] = arith.subi %[[ARG1]], %[[C8]] : index +// CHECK: %[[MAX1_4:.*]] = arith.maxsi %[[SUB1_2]], %[[C0]] : index +// CHECK: %[[MIN1_4:.*]] = arith.minsi %[[MAX1_4]], %[[C8]] : index +// CHECK: %[[MASK11:.*]] = vector.create_mask %[[MIN0_4]], %[[MIN1_4]] : vector<8x8xi1> +// CHECK: %[[INS11:.*]] = vector.insert_strided_slice %[[MASK11]], %[[INS10]] {offsets = [8, 8], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: return %[[INS11]] : vector<16x16xi1> + +func.func @vector_create_mask_constant_dim_sizes() -> vector<16x16xi1> { + %cst16 = arith.constant 16 : index + %0 = vector.create_mask %cst16, %cst16 : vector<16x16xi1> + return %0 : vector<16x16xi1> +} + +// CHECK-LABEL: func @vector_create_mask_constant_dim_sizes() -> vector<16x16xi1> { +// CHECK: %[[CST:.*]] = arith.constant dense<false> : vector<16x16xi1> +// CHECK: %[[CST_0:.*]] = arith.constant dense<true> : vector<8x8xi1> +// CHECK: %[[S0:.*]] = vector.insert_strided_slice %[[CST_0]], %[[CST]] {offsets = [0, 0], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[S1:.*]] = vector.insert_strided_slice %[[CST_0]], %[[S0]] {offsets = [0, 8], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[S2:.*]] = vector.insert_strided_slice %[[CST_0]], %[[S1]] {offsets = [8, 0], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: %[[S3:.*]] = vector.insert_strided_slice %[[CST_0]], %[[S2]] {offsets = [8, 8], strides = [1, 1]} : vector<8x8xi1> into vector<16x16xi1> +// CHECK: return %[[S3]] : vector<16x16xi1> + func.func @shape_cast_1D(%v: vector<16xf32>) -> vector<2x2x4xf32> { %0 = vector.shape_cast %v : vector<16xf32> to vector<2x2x4xf32> diff --git a/mlir/test/lib/Dialect/Vector/TestVectorTransforms.cpp b/mlir/test/lib/Dialect/Vector/TestVectorTransforms.cpp index e8ea0cc02d7f6..f834d0cdd42bd 100644 --- a/mlir/test/lib/Dialect/Vector/TestVectorTransforms.cpp +++ b/mlir/test/lib/Dialect/Vector/TestVectorTransforms.cpp @@ -178,6 +178,12 @@ struct TestVectorUnrollingPatterns .setFilterConstraint([](Operation *op) { return success(isa<vector::StepOp>(op)); })); + populateVectorUnrollPatterns( + patterns, UnrollVectorOptions() + .setNativeShape(ArrayRef<int64_t>{8, 8}) + .setFilterConstraint([](Operation *op) { + return success(isa<vector::CreateMaskOp>(op)); + })); populateVectorUnrollPatterns( patterns, UnrollVectorOptions() >From 60a2c3fce321569b5f6cb5c9a84b3a2c3d618a03 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Wed, 3 Dec 2025 16:42:19 -0500 Subject: [PATCH 5/6] DAG: Use poison for filler values on legalize error paths (#170556) --- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 8336e1d1f4134..e739659d68561 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -2130,7 +2130,7 @@ SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, if (const char *LibcallName = TLI.getLibcallName(LC)) Callee = DAG.getExternalSymbol(LibcallName, CodePtrTy); else { - Callee = DAG.getUNDEF(CodePtrTy); + Callee = DAG.getPOISON(CodePtrTy); DAG.getContext()->emitError(Twine("no libcall available for ") + Node->getOperationName(&DAG)); } @@ -4992,7 +4992,7 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) { // If the exponent does not match with sizeof(int) a libcall to // RTLIB::POWI would use the wrong type for the argument. DAG.getContext()->emitError("POWI exponent does not match sizeof(int)"); - Results.push_back(DAG.getUNDEF(Node->getValueType(0))); + Results.push_back(DAG.getPOISON(Node->getValueType(0))); break; } ExpandFPLibCall(Node, LC, Results); >From a8e5a3547900b262016eefb0e81897b2fd9d2f5e Mon Sep 17 00:00:00 2001 From: "Balaji V. Iyer" <[email protected]> Date: Thu, 18 Dec 2025 20:08:30 -0600 Subject: [PATCH 6/6] Added changes suggested by reviewers --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/AST/ExprConstant.cpp | 2 +- clang/test/AST/array-overflow-index.cpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 clang/test/AST/array-overflow-index.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 654a8e48cd104..46545e6f26f38 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -579,6 +579,8 @@ Bug Fixes to C++ Support - Fix a crash when extracting unavailable member type from alias in template deduction. (#GH165560) - Fix incorrect diagnostics for lambdas with init-captures inside braced initializers. (#GH163498) - Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) (#GH156579) +- Fixed a crash where the constexpr evaluation for an array index is failing when it is not + representable as a 64 bit number (#GH154713) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4057183ae21c9..3856a28b2190f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9752,7 +9752,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { // If Index cannot be represented as a 64 bit integer, return // unsuccessful. if (!Index.tryExtValue().has_value()) - return Error(E); + return false; HandleLValueVectorElement(Info, E, Result, VT->getElementType(), VT->getNumElements(), Index.getExtValue()); diff --git a/clang/test/AST/array-overflow-index.cpp b/clang/test/AST/array-overflow-index.cpp new file mode 100644 index 0000000000000..197f8628d0f71 --- /dev/null +++ b/clang/test/AST/array-overflow-index.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 --std=c++17 -fexperimental-new-constant-interpreter -verify %s + + +constexpr int __attribute__((vector_size(4))) test_vector = {1}; + +// expected-error@+1 {{constexpr function never produces a constant expression}} +constexpr int get_last_element(void) { + // expected-note@+1 {{cannot refer to element 18446744073709551615 of array of 1 element in a constant expression}} + return test_vector[~0UL]; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
