https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/139146
>From 11de7d363ae9f06e98f15fc5c492e74a660693f8 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Thu, 8 May 2025 22:10:39 +0200 Subject: [PATCH 1/3] [CIR] Upstream insert op for VectorType --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 37 ++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 38 ++++-- clang/lib/CIR/CodeGen/CIRGenValue.h | 27 ++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 11 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 ++ clang/test/CIR/CodeGen/vector-ext.cpp | 123 ++++++++++++++++++ clang/test/CIR/CodeGen/vector.cpp | 123 ++++++++++++++++++ clang/test/CIR/IR/vector.cir | 38 ++++++ 8 files changed, 397 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7aff5edb88167..4b071680c4c1e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1969,6 +1969,43 @@ def VecCreateOp : CIR_Op<"vec.create", [Pure]> { let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// VecInsertOp +//===----------------------------------------------------------------------===// + +def VecInsertOp : CIR_Op<"vec.insert", [Pure, + TypesMatchWith<"argument type matches vector element type", "vec", "value", + "cast<VectorType>($_self).getElementType()">, + AllTypesMatch<["result", "vec"]>]> { + + let summary = "Insert one element into a vector object"; + let description = [{ + The `cir.vec.insert` operation replaces the element of the given vector at + the given index with the given value. The new vector with the inserted + element is returned. + + ```mlir + %value = cir.const #cir.int<5> : !s32i + %index = cir.const #cir.int<2> : !s32i + %vec_tmp = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> + %new_vec = cir.vec.insert %index, %vec_tmp[%value : !s32i] : !cir.vector<4 x !s32i> + ``` + }]; + + let arguments = (ins + CIR_VectorType:$vec, + AnyType:$value, + CIR_AnyFundamentalIntType:$index + ); + + let results = (outs CIR_VectorType:$result); + + let assemblyFormat = [{ + $value `,` $vec `[` $index `:` type($index) `]` attr-dict `:` + qualified(type($vec)) + }]; +} + //===----------------------------------------------------------------------===// // VecExtractOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 711a65215b043..fd70b0d9b667e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -205,6 +205,17 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr, void CIRGenFunction::emitStoreThroughLValue(RValue src, LValue dst, bool isInit) { if (!dst.isSimple()) { + if (dst.isVectorElt()) { + // Read/modify/write the vector, inserting the new element + const mlir::Location loc = dst.getVectorPointer().getLoc(); + const mlir::Value vector = + builder.createLoad(loc, dst.getVectorAddress().getPointer()); + const mlir::Value newVector = builder.create<cir::VecInsertOp>( + loc, vector, src.getScalarVal(), dst.getVectorIdx()); + builder.createStore(loc, newVector, dst.getVectorAddress().getPointer()); + return; + } + cgm.errorNYI(dst.getPointer().getLoc(), "emitStoreThroughLValue: non-simple lvalue"); return; @@ -418,6 +429,13 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) { if (lv.isSimple()) return RValue::get(emitLoadOfScalar(lv, loc)); + if (lv.isVectorElt()) { + auto load = + builder.createLoad(getLoc(loc), lv.getVectorAddress().getPointer()); + return RValue::get(builder.create<cir::VecExtractOp>(getLoc(loc), load, + lv.getVectorIdx())); + } + cgm.errorNYI(loc, "emitLoadOfLValue"); return RValue::get(nullptr); } @@ -638,12 +656,6 @@ static Address emitArraySubscriptPtr(CIRGenFunction &cgf, LValue CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { - if (e->getBase()->getType()->isVectorType() && - !isa<ExtVectorElementExpr>(e->getBase())) { - cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: VectorType"); - return LValue::makeAddr(Address::invalid(), e->getType(), LValueBaseInfo()); - } - if (isa<ExtVectorElementExpr>(e->getBase())) { cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: ExtVectorElementExpr"); @@ -666,18 +678,26 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { assert((e->getIdx() == e->getLHS() || e->getIdx() == e->getRHS()) && "index was neither LHS nor RHS"); - auto emitIdxAfterBase = [&]() -> mlir::Value { + auto emitIdxAfterBase = [&](bool promote) -> mlir::Value { const mlir::Value idx = emitScalarExpr(e->getIdx()); // Extend or truncate the index type to 32 or 64-bits. auto ptrTy = mlir::dyn_cast<cir::PointerType>(idx.getType()); - if (ptrTy && mlir::isa<cir::IntType>(ptrTy.getPointee())) + if (promote && ptrTy && mlir::isa<cir::IntType>(ptrTy.getPointee())) cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: index type cast"); return idx; }; - const mlir::Value idx = emitIdxAfterBase(); + if (e->getBase()->getType()->isVectorType() && + !isa<ExtVectorElementExpr>(e->getBase())) { + const mlir::Value idx = emitIdxAfterBase(/*promote=*/false); + const LValue lhs = emitLValue(e->getBase()); + return LValue::makeVectorElt(lhs.getAddress(), idx, e->getBase()->getType(), + lhs.getBaseInfo()); + } + + const mlir::Value idx = emitIdxAfterBase(/*promote=*/true); if (const Expr *array = getSimpleArrayDecayOperand(e->getBase())) { LValue arrayLV; if (const auto *ase = dyn_cast<ArraySubscriptExpr>(array)) diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h b/clang/lib/CIR/CodeGen/CIRGenValue.h index 1c453dc9c86b5..2b292cbf8ac98 100644 --- a/clang/lib/CIR/CodeGen/CIRGenValue.h +++ b/clang/lib/CIR/CodeGen/CIRGenValue.h @@ -115,6 +115,7 @@ class LValue { // this is the alignment of the whole vector) unsigned alignment; mlir::Value v; + mlir::Value vectorIdx; // Index for vector subscript mlir::Type elementType; LValueBaseInfo baseInfo; @@ -135,6 +136,7 @@ class LValue { public: bool isSimple() const { return lvType == Simple; } + bool isVectorElt() const { return lvType == VectorElt; } bool isBitField() const { return lvType == BitField; } // TODO: Add support for volatile @@ -175,6 +177,31 @@ class LValue { r.initialize(t, t.getQualifiers(), address.getAlignment(), baseInfo); return r; } + + Address getVectorAddress() const { + return Address(getVectorPointer(), elementType, getAlignment()); + } + + mlir::Value getVectorPointer() const { + assert(isVectorElt()); + return v; + } + + mlir::Value getVectorIdx() const { + assert(isVectorElt()); + return vectorIdx; + } + + static LValue makeVectorElt(Address vecAddress, mlir::Value index, + clang::QualType t, LValueBaseInfo baseInfo) { + LValue r; + r.lvType = VectorElt; + r.v = vecAddress.getPointer(); + r.elementType = vecAddress.getElementType(); + r.vectorIdx = index; + r.initialize(t, t.getQualifiers(), vecAddress.getAlignment(), baseInfo); + return r; + } }; /// An aggregate value slot. diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 66f29f8f6cdd0..9d8a8e337140f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1601,7 +1601,8 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMTrapOpLowering, CIRToLLVMUnaryOpLowering, CIRToLLVMVecCreateOpLowering, - CIRToLLVMVecExtractOpLowering + CIRToLLVMVecExtractOpLowering, + CIRToLLVMVecInsertOpLowering // clang-format on >(converter, patterns.getContext()); @@ -1718,6 +1719,14 @@ mlir::LogicalResult CIRToLLVMVecExtractOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMVecInsertOpLowering::matchAndRewrite( + cir::VecInsertOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + rewriter.replaceOpWithNewOp<mlir::LLVM::InsertElementOp>( + op, adaptor.getVec(), adaptor.getValue(), adaptor.getIndex()); + return mlir::success(); +} + std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { return std::make_unique<ConvertCIRToLLVMPass>(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 026505ea31b4c..6539fd04d7487 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -313,6 +313,16 @@ class CIRToLLVMVecExtractOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVecInsertOpLowering + : public mlir::OpConversionPattern<cir::VecInsertOp> { +public: + using mlir::OpConversionPattern<cir::VecInsertOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VecInsertOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/test/CIR/CodeGen/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp index 0756497bf6b96..095bff13ddefc 100644 --- a/clang/test/CIR/CodeGen/vector-ext.cpp +++ b/clang/test/CIR/CodeGen/vector-ext.cpp @@ -213,3 +213,126 @@ void foo4() { // OGCG: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 // OGCG: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP1]], i32 %[[TMP2]] // OGCG: store i32 %[[ELE]], ptr %[[INIT]], align 4 + +void foo5() { + vi4 a = { 1, 2, 3, 4 }; + + a[2] = 5; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[TMP:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[CONST_VAL]], %[[TMP]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP]], i32 5, i32 2 +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP]], i32 5, i32 2 +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo6() { + vi4 a = { 1, 2, 3, 4 }; + int idx = 2; + int value = 5; + a[idx] = value; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["idx", init] +// CIR: %[[VAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["value", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: cir.store %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store %[[CONST_VAL]], %[[VAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP1:.*]] = cir.load %[[VAL]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[TMP2:.*]] = cir.load %[[IDX]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[TMP3:.*]] = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[TMP1]], %[[TMP3]][%[[TMP2]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[IDX:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[VAL:.*]] = alloca i32, i64 1, align 4 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %1, align 16 +// LLVM: store i32 2, ptr %[[IDX]], align 4 +// LLVM: store i32 5, ptr %[[VAL]], align 4 +// LLVM: %[[TMP1:.*]] = load i32, ptr %[[VAL]], align 4 +// LLVM: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 +// LLVM: %[[TMP3:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP3]], i32 %[[TMP1]], i32 %[[TMP2]] +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[IDX:.*]] = alloca i32, align 4 +// OGCG: %[[VAL:.*]] = alloca i32, align 4 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: store i32 2, ptr %[[IDX]], align 4 +// OGCG: store i32 5, ptr %[[VAL]], align 4 +// OGCG: %[[TMP1:.*]] = load i32, ptr %[[VAL]], align 4 +// OGCG: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 +// OGCG: %[[TMP3:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP3]], i32 %[[TMP1]], i32 %[[TMP2]] +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo7() { + vi4 a = {1, 2, 3, 4}; + a[2] += 5; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[TMP:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ELE:.*]] = cir.vec.extract %[[TMP]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: %[[RES:.*]] = cir.binop(add, %[[ELE]], %[[CONST_VAL]]) nsw : !s32i +// CIR: %[[TMP2:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[RES]], %[[TMP2]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP]], i32 2 +// LLVM: %[[RES:.*]] = add nsw i32 %[[ELE]], 5 +// LLVM: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP]], i32 2 +// OGCG: %[[RES:.*]] = add nsw i32 %[[ELE]], 5 +// OGCG: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 diff --git a/clang/test/CIR/CodeGen/vector.cpp b/clang/test/CIR/CodeGen/vector.cpp index 530018108c6d9..aaf53b9e02b9a 100644 --- a/clang/test/CIR/CodeGen/vector.cpp +++ b/clang/test/CIR/CodeGen/vector.cpp @@ -201,3 +201,126 @@ void foo4() { // OGCG: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 // OGCG: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP1]], i32 %[[TMP2]] // OGCG: store i32 %[[ELE]], ptr %[[INIT]], align 4 + +void foo5() { + vi4 a = { 1, 2, 3, 4 }; + + a[2] = 5; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[TMP:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[CONST_VAL]], %[[TMP]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP]], i32 5, i32 2 +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP]], i32 5, i32 2 +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo6() { + vi4 a = { 1, 2, 3, 4 }; + int idx = 2; + int value = 5; + a[idx] = value; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[IDX:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["idx", init] +// CIR: %[[VAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["value", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: cir.store %[[CONST_IDX]], %[[IDX]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: cir.store %[[CONST_VAL]], %[[VAL]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[TMP1:.*]] = cir.load %[[VAL]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[TMP2:.*]] = cir.load %[[IDX]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[TMP3:.*]] = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[TMP1]], %[[TMP3]][%[[TMP2]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[IDX:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[VAL:.*]] = alloca i32, i64 1, align 4 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %1, align 16 +// LLVM: store i32 2, ptr %[[IDX]], align 4 +// LLVM: store i32 5, ptr %[[VAL]], align 4 +// LLVM: %[[TMP1:.*]] = load i32, ptr %[[VAL]], align 4 +// LLVM: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 +// LLVM: %[[TMP3:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP3]], i32 %[[TMP1]], i32 %[[TMP2]] +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[IDX:.*]] = alloca i32, align 4 +// OGCG: %[[VAL:.*]] = alloca i32, align 4 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: store i32 2, ptr %[[IDX]], align 4 +// OGCG: store i32 5, ptr %[[VAL]], align 4 +// OGCG: %[[TMP1:.*]] = load i32, ptr %[[VAL]], align 4 +// OGCG: %[[TMP2:.*]] = load i32, ptr %[[IDX]], align 4 +// OGCG: %[[TMP3:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP3]], i32 %[[TMP1]], i32 %[[TMP2]] +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo7() { + vi4 a = {1, 2, 3, 4}; + a[2] += 5; +} + +// CIR: %[[VEC:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_VAL]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_VAL:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_IDX:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[TMP:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[ELE:.*]] = cir.vec.extract %[[TMP]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: %[[RES:.*]] = cir.binop(add, %[[ELE]], %[[CONST_VAL]]) nsw : !s32i +// CIR: %[[TMP2:.*]] = cir.load %[[VEC]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[NEW_VEC:.*]] = cir.vec.insert %[[RES]], %[[TMP2]][%[[CONST_IDX]] : !s32i] : !cir.vector<4 x !s32i> +// CIR: cir.store %[[NEW_VEC]], %[[VEC]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// LLVM: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP]], i32 2 +// LLVM: %[[RES:.*]] = add nsw i32 %[[ELE]], 5 +// LLVM: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// LLVM: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 +// LLVM: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +// OGCG: %[[VEC:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC]], align 16 +// OGCG: %[[TMP:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[ELE:.*]] = extractelement <4 x i32> %[[TMP]], i32 2 +// OGCG: %[[RES:.*]] = add nsw i32 %[[ELE]], 5 +// OGCG: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 +// OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 +// OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 diff --git a/clang/test/CIR/IR/vector.cir b/clang/test/CIR/IR/vector.cir index aeb268e84c71c..21a1f0a7559c4 100644 --- a/clang/test/CIR/IR/vector.cir +++ b/clang/test/CIR/IR/vector.cir @@ -97,4 +97,42 @@ cir.func @vector_extract_element_test() { // CHECK: cir.return // CHECK: } +cir.func @vector_insert_element_test() { + %0 = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] + %1 = cir.const #cir.int<1> : !s32i + %2 = cir.const #cir.int<2> : !s32i + %3 = cir.const #cir.int<3> : !s32i + %4 = cir.const #cir.int<4> : !s32i + %5 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> + cir.store %5, %0 : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + %6 = cir.const #cir.int<5> : !s32i + %7 = cir.const #cir.int<2> : !s32i + %8 = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> + %9 = cir.vec.extract %8[%7 : !s32i] : !cir.vector<4 x !s32i> + %10 = cir.binop(add, %9, %6) nsw : !s32i + %11 = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> + %12 = cir.vec.insert %10, %11[%7 : !s32i] : !cir.vector<4 x !s32i> + cir.store %12, %0 : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + cir.return +} + +// CHECK: cir.func @vector_insert_element_test() { +// CHECK: %0 = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CHECK: %1 = cir.const #cir.int<1> : !s32i +// CHECK: %2 = cir.const #cir.int<2> : !s32i +// CHECK: %3 = cir.const #cir.int<3> : !s32i +// CHECK: %4 = cir.const #cir.int<4> : !s32i +// CHECK: %5 = cir.vec.create(%1, %2, %3, %4 : !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CHECK: cir.store %5, %0 : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CHECK: %6 = cir.const #cir.int<5> : !s32i +// CHECK: %7 = cir.const #cir.int<2> : !s32i +// CHECK: %8 = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CHECK: %9 = cir.vec.extract %8[%7 : !s32i] : !cir.vector<4 x !s32i> +// CHECK: %10 = cir.binop(add, %9, %6) nsw : !s32i +// CHECK: %11 = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CHECK: %12 = cir.vec.insert %10, %11[%7 : !s32i] : !cir.vector<4 x !s32i> +// CHECK: cir.store %12, %0 : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CHECK: cir.return +// CHECK: } + } >From b442dd0b7f9f980026ce5e9cb5328232dfc3c814 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Fri, 9 May 2025 18:29:00 +0200 Subject: [PATCH 2/3] Address code review comments --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++-- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4b071680c4c1e..39266c699890e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1981,14 +1981,14 @@ def VecInsertOp : CIR_Op<"vec.insert", [Pure, let summary = "Insert one element into a vector object"; let description = [{ The `cir.vec.insert` operation replaces the element of the given vector at - the given index with the given value. The new vector with the inserted + the given index with the given value. The new vector with the inserted element is returned. ```mlir %value = cir.const #cir.int<5> : !s32i %index = cir.const #cir.int<2> : !s32i %vec_tmp = cir.load %0 : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> - %new_vec = cir.vec.insert %index, %vec_tmp[%value : !s32i] : !cir.vector<4 x !s32i> + %new_vec = cir.vec.insert %value, %vec_tmp[%index : !s32i] : !cir.vector<4 x !s32i> ``` }]; diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index fd70b0d9b667e..038696182f6c8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -430,7 +430,7 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) { return RValue::get(emitLoadOfScalar(lv, loc)); if (lv.isVectorElt()) { - auto load = + const mlir::Value load = builder.createLoad(getLoc(loc), lv.getVectorAddress().getPointer()); return RValue::get(builder.create<cir::VecExtractOp>(getLoc(loc), load, lv.getVectorIdx())); @@ -683,12 +683,14 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) { // Extend or truncate the index type to 32 or 64-bits. auto ptrTy = mlir::dyn_cast<cir::PointerType>(idx.getType()); - if (promote && ptrTy && mlir::isa<cir::IntType>(ptrTy.getPointee())) + if (promote && ptrTy && ptrTy.isPtrTo<cir::IntType>()) cgm.errorNYI(e->getSourceRange(), "emitArraySubscriptExpr: index type cast"); return idx; }; + // If the base is a vector type, then we are forming a vector element + // with this subscript. if (e->getBase()->getType()->isVectorType() && !isa<ExtVectorElementExpr>(e->getBase())) { const mlir::Value idx = emitIdxAfterBase(/*promote=*/false); >From 56f60f70e14718cdd9e7063e7e58d813d9bf52b8 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Fri, 9 May 2025 20:35:35 +0200 Subject: [PATCH 3/3] Improve the description of VecInsertOp --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 39266c699890e..e8020b0ad803a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1980,9 +1980,8 @@ def VecInsertOp : CIR_Op<"vec.insert", [Pure, let summary = "Insert one element into a vector object"; let description = [{ - The `cir.vec.insert` operation replaces the element of the given vector at - the given index with the given value. The new vector with the inserted - element is returned. + The `cir.vec.insert` operation produces a new vector by replacing + the element of the input vector at `index` with `value`. ```mlir %value = cir.const #cir.int<5> : !s32i _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits