diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index b8abd89f35d2..4a3f7331ccef 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3132,6 +3132,58 @@ def CIR_GetMethodOp : CIR_Op<"get_method"> { let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// GetElementOp +//===----------------------------------------------------------------------===// + +def CIR_GetElementOp : CIR_Op<"get_element"> { + let summary = "Get the address of an array element"; + let description = [{ + The `cir.get_element` operation gets the address of a particular element + from the `base` array. + + It expects a pointer to the `base` array and the `index` of the element. + + Example: + ```mlir + // Suppose we have a array. + !s32i = !cir.int + !arr_ty = !cir.array + + // Get the address of the element at index 1. + %elem_1 = cir.get_element %0[1] : (!cir.ptr, !s32i) -> !cir.ptr + + // Get the address of the element at index %i. + %i = ... + %elem_i = cir.get_element %0[%i] : (!cir.ptr, !s32i) -> !cir.ptr + ``` + }]; + + let arguments = (ins + Arg:$base, + Arg:$index + ); + + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $base `[` $index `]` `:` `(` qualified(type($base)) `,` qualified(type($index)) `)` + `->` qualified(type($result)) attr-dict + }]; + + let extraClassDeclaration = [{ + // Get the type of the element. + mlir::Type getElementType() { + return getType().getPointee(); + } + cir::PointerType getBaseType() { + return mlir::cast(getBase().getType()); + } + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // VecInsertOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp index 437db1a7fdd8..5322865b9474 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.cpp @@ -28,11 +28,48 @@ mlir::Value CIRGenBuilderTy::maybeBuildArrayDecay(mlir::Location loc, return arrayPtr; } -mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin, +mlir::Value CIRGenBuilderTy::promoteArrayIndex(const clang::TargetInfo &ti, + mlir::Location loc, + mlir::Value index) { + // Get the array index type. + auto arrayIndexWidth = ti.getTypeWidth(clang::TargetInfo::IntType::SignedInt); + mlir::Type arrayIndexType = getSIntNTy(arrayIndexWidth); + + // If this is a boolean, zero-extend it to the array index type. + if (auto boolTy = mlir::dyn_cast(index.getType())) + return create(loc, arrayIndexType, cir::CastKind::bool_to_int, + index); + + // If this an integer, ensure that it is at least as width as the array index + // type. + if (auto intTy = mlir::dyn_cast(index.getType())) { + if (intTy.getWidth() < arrayIndexWidth) + return create(loc, arrayIndexType, cir::CastKind::integral, + index); + } + + return index; +} + +mlir::Value CIRGenBuilderTy::getArrayElement(const clang::TargetInfo &ti, + mlir::Location arrayLocBegin, mlir::Location arrayLocEnd, mlir::Value arrayPtr, mlir::Type eltTy, mlir::Value idx, bool shouldDecay) { + auto arrayPtrTy = mlir::dyn_cast(arrayPtr.getType()); + assert(arrayPtrTy && "expected pointer type"); + + // If the array pointer is not decayed, emit a GetElementOp. + auto arrayTy = mlir::dyn_cast(arrayPtrTy.getPointee()); + if (shouldDecay && arrayTy && arrayTy == eltTy) { + auto eltPtrTy = + getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace()); + return create(arrayLocEnd, eltPtrTy, arrayPtr, + promoteArrayIndex(ti, arrayLocBegin, idx)); + } + + // If we don't have sufficient type information, emit a PtrStrideOp. mlir::Value basePtr = arrayPtr; if (shouldDecay) basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index aaeaa3ea5701..75c9040609df 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDataLayout.h" @@ -1030,10 +1031,15 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create(loc, resultTy, objectPtr, memberPtr); } + /// Promote a value for use as an array index. + mlir::Value promoteArrayIndex(const clang::TargetInfo &TargetInfo, + mlir::Location loc, mlir::Value index); + /// Create a cir.ptr_stride operation to get access to an array element. /// idx is the index of the element to access, shouldDecay is true if the /// result should decay to a pointer to the element type. - mlir::Value getArrayElement(mlir::Location arrayLocBegin, + mlir::Value getArrayElement(const clang::TargetInfo &targetInfo, + mlir::Location arrayLocBegin, mlir::Location arrayLocEnd, mlir::Value arrayPtr, mlir::Type eltTy, mlir::Value idx, bool shouldDecay); diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index fc7ad46937d4..2119da53af19 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1710,8 +1710,8 @@ emitArraySubscriptPtr(CIRGenFunction &CGF, mlir::Location beginLoc, // that would enhance tracking this later in CIR? if (inbounds) assert(!cir::MissingFeatures::emitCheckedInBoundsGEP() && "NYI"); - return CGM.getBuilder().getArrayElement(beginLoc, endLoc, ptr, eltTy, idx, - shouldDecay); + return CGM.getBuilder().getArrayElement(CGF.getTarget(), beginLoc, endLoc, + ptr, eltTy, idx, shouldDecay); } static QualType getFixedSizeElementType(const ASTContext &astContext, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp index cdd7a9a42408..9bd79e14ac2d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp @@ -954,9 +954,9 @@ void AggExprEmitter::VisitCXXStdInitializerListExpr( ArrayType->getElementType()) && "Expected std::initializer_list second field to be const E *"); - auto ArrayEnd = - Builder.getArrayElement(loc, loc, ArrayPtr.getPointer(), - ArrayPtr.getElementType(), Size, false); + auto ArrayEnd = Builder.getArrayElement( + CGF.getTarget(), loc, loc, ArrayPtr.getPointer(), + ArrayPtr.getElementType(), Size, false); CGF.emitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); } } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 18ef47095e6e..d06b1f269df7 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -3837,6 +3837,18 @@ LogicalResult cir::GetMethodOp::verify() { return mlir::success(); } +//===----------------------------------------------------------------------===// +// GetMemberOp Definitions +//===----------------------------------------------------------------------===// + +LogicalResult cir::GetElementOp::verify() { + auto arrayTy = mlir::cast(getBaseType().getPointee()); + if (getElementType() != arrayTy.getElementType()) + return emitError() << "element type mismatch"; + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // InlineAsmOp Definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp index af909005b4a0..97e34ab21690 100644 --- a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp @@ -1254,6 +1254,12 @@ void LifetimeCheckPass::updatePointsTo(mlir::Value addr, mlir::Value data, return; } + if (auto getElemOp = mlir::dyn_cast(dataSrcOp)) { + getPmap()[addr].clear(); + getPmap()[addr].insert(State::getLocalValue(getElemOp.getBase())); + return; + } + // Initializes ptr types out of known lib calls marked with pointer // attributes. TODO: find a better way to tag this. if (auto callOp = dyn_cast(dataSrcOp)) { @@ -1945,8 +1951,7 @@ void LifetimeCheckPass::dumpPmap(PMapType &pmap) { int entry = 0; for (auto &mapEntry : pmap) { llvm::errs() << " " << entry << ": " << getVarNameFromValue(mapEntry.first) - << " " - << "=> "; + << " => "; printPset(mapEntry.second); llvm::errs() << "\n"; entry++; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e910a809ca71..bde3acb4a002 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -951,6 +951,51 @@ static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter, return rewriter.create(loc, llvmDstIntTy, llvmSrc); } +static mlir::Value promoteIndex(mlir::ConversionPatternRewriter &rewriter, + mlir::Value index, uint64_t layoutWidth, + bool isUnsigned) { + auto indexOp = index.getDefiningOp(); + if (!indexOp) + return index; + + auto indexType = mlir::cast(index.getType()); + auto width = indexType.getWidth(); + if (layoutWidth == width) + return index; + + // If the index definition is a unary minus (index = sub 0, x), then we need + // to + bool rewriteSub = false; + auto sub = mlir::dyn_cast(indexOp); + if (sub) { + if (auto lhsConst = dyn_cast( + sub.getOperand(0).getDefiningOp())) { + auto lhsConstInt = mlir::dyn_cast(lhsConst.getValue()); + if (lhsConstInt && lhsConstInt.getValue() == 0) { + rewriteSub = true; + index = sub.getOperand(1); + } + } + } + + // Handle the cast + auto llvmDstType = mlir::IntegerType::get(rewriter.getContext(), layoutWidth); + index = getLLVMIntCast(rewriter, index, llvmDstType, isUnsigned, width, + layoutWidth); + + if (rewriteSub) { + index = rewriter.create( + index.getLoc(), + rewriter.create(index.getLoc(), index.getType(), + 0), + index); + // TODO: check if the sub is trivially dead now. + rewriter.eraseOp(sub); + } + + return index; +} + mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -964,43 +1009,18 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( // make it i8 instead. if (mlir::isa(elementTy) || mlir::isa(elementTy)) - elementTy = mlir::IntegerType::get(elementTy.getContext(), 8, - mlir::IntegerType::Signless); + elementTy = mlir::IntegerType::get(ctx, 8, mlir::IntegerType::Signless); // Zero-extend, sign-extend or trunc the pointer value. auto index = adaptor.getStride(); - auto width = mlir::cast(index.getType()).getWidth(); mlir::DataLayout LLVMLayout(ptrStrideOp->getParentOfType()); - auto layoutWidth = - LLVMLayout.getTypeIndexBitwidth(adaptor.getBase().getType()); - auto indexOp = index.getDefiningOp(); - if (indexOp && layoutWidth && width != *layoutWidth) { - // If the index comes from a subtraction, make sure the extension happens - // before it. To achieve that, look at unary minus, which already got - // lowered to "sub 0, x". - auto sub = dyn_cast(indexOp); - auto unary = dyn_cast_if_present( - ptrStrideOp.getStride().getDefiningOp()); - bool rewriteSub = - unary && unary.getKind() == cir::UnaryOpKind::Minus && sub; - if (rewriteSub) - index = indexOp->getOperand(1); - - // Handle the cast - auto llvmDstType = mlir::IntegerType::get(ctx, *layoutWidth); - index = getLLVMIntCast(rewriter, index, llvmDstType, - ptrStrideOp.getStride().getType().isUnsigned(), - width, *layoutWidth); - - // Rewrite the sub in front of extensions/trunc - if (rewriteSub) { - index = rewriter.create( - index.getLoc(), - rewriter.create(index.getLoc(), - index.getType(), 0), - index); - rewriter.eraseOp(sub); - } + if (auto layoutWidth = + LLVMLayout.getTypeIndexBitwidth(adaptor.getBase().getType())) { + bool isUnsigned = false; + if (auto strideTy = + mlir::dyn_cast(ptrStrideOp.getOperand(1).getType())) + isUnsigned = strideTy.isUnsigned(); + index = promoteIndex(rewriter, index, *layoutWidth, isUnsigned); } rewriter.replaceOpWithNewOp( @@ -1008,6 +1028,48 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite( + cir::GetElementOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + + if (auto arrayTy = + mlir::dyn_cast(op.getBaseType().getPointee())) { + auto *tc = getTypeConverter(); + const auto llResultTy = tc->convertType(op.getType()); + auto elementTy = convertTypeForMemory(*tc, dataLayout, op.getElementType()); + auto *ctx = elementTy.getContext(); + + // void and function types doesn't really have a layout to use in GEPs, + // make it i8 instead. + if (mlir::isa(elementTy) || + mlir::isa(elementTy)) + elementTy = mlir::IntegerType::get(ctx, 8, mlir::IntegerType::Signless); + + // Zero-extend, sign-extend or trunc the index value. + auto index = adaptor.getIndex(); + mlir::DataLayout LLVMLayout(op->getParentOfType()); + if (auto layoutWidth = + LLVMLayout.getTypeIndexBitwidth(adaptor.getBase().getType())) { + bool isUnsigned = false; + if (auto strideTy = dyn_cast(op.getOperand(1).getType())) + isUnsigned = strideTy.isUnsigned(); + index = promoteIndex(rewriter, index, *layoutWidth, isUnsigned); + } + + // Since the base address is a pointer to an aggregate, the first + // offset is always zero. The second offset tell us which member it + // will access. + const auto llArrayTy = getTypeConverter()->convertType(arrayTy); + llvm::SmallVector offset{0, index}; + rewriter.replaceOpWithNewOp(op, llResultTy, llArrayTy, + adaptor.getBase(), offset); + + return mlir::success(); + } + + llvm_unreachable("NYI, GetElementOp lowering to LLVM for non-Array"); +} + mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite( cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -4388,6 +4450,7 @@ void populateCIRToLLVMConversionPatterns( patterns.add< // clang-format off CIRToLLVMPtrStrideOpLowering, + CIRToLLVMGetElementOpLowering, CIRToLLVMInlineAsmOpLowering // clang-format on >(converter, patterns.getContext(), dataLayout); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index f62542149a29..da5e598bc4bf 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -158,6 +158,22 @@ class CIRToLLVMPtrStrideOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMGetElementOpLowering + : public mlir::OpConversionPattern { + mlir::DataLayout const &dataLayout; + +public: + CIRToLLVMGetElementOpLowering(const mlir::TypeConverter &typeConverter, + mlir::MLIRContext *context, + mlir::DataLayout const &dataLayout) + : OpConversionPattern(typeConverter, context), dataLayout(dataLayout) {} + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::GetElementOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMBaseClassAddrOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 1d8ccc652f39..1a3cb5db1fa4 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1332,6 +1332,58 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { } }; +class CIRGetElementOpLowering + : public mlir::OpConversionPattern { + using mlir::OpConversionPattern::OpConversionPattern; + + bool isLoadStoreOrGetProducer(cir::GetElementOp op) const { + for (auto *user : op->getUsers()) { + if (!op->isBeforeInBlock(user)) + return false; + if (isa(*user)) + continue; + return false; + } + return true; + } + + // Rewrite + // cir.get_element(%base[%index]) + // to + // memref.reinterpret_cast (%base, %stride) + // + // MemRef Dialect doesn't have GEP-like operation. memref.reinterpret_cast + // only been used to propagate %base and %index to memref.load/store and + // should be erased after the conversion. + mlir::LogicalResult + matchAndRewrite(cir::GetElementOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + // Only rewrite if all users are load/stores. + if (!isLoadStoreOrGetProducer(op)) + return mlir::failure(); + + // Cast the index to the index type, if needed. + auto index = adaptor.getIndex(); + auto indexType = rewriter.getIndexType(); + if (index.getType() != indexType) + index = rewriter.create(op.getLoc(), indexType, + index); + + // Convert the destination type. + auto dstType = + cast(getTypeConverter()->convertType(op.getType())); + + // Replace the GetElementOp with a memref.reinterpret_cast. + rewriter.replaceOpWithNewOp( + op, dstType, adaptor.getBase(), + /* offset */ index, + /* sizes */ std::nullopt, + /* strides */ std::nullopt); + + return mlir::success(); + } +}; + class CIRPtrStrideOpLowering : public mlir::OpConversionPattern { public: @@ -1363,7 +1415,7 @@ class CIRPtrStrideOpLowering for (auto *user : op->getUsers()) { if (!op->isBeforeInBlock(user)) return false; - if (isa(*user) || isa(*user)) + if (isa(*user)) continue; auto castOp = dyn_cast(*user); if (castOp && (castOp.getKind() == cir::CastKind::array_to_ptrdecay)) @@ -1455,17 +1507,18 @@ void populateCIRToMLIRConversionPatterns(mlir::RewritePatternSet &patterns, CIRFuncOpLowering, CIRScopeOpLowering, CIRBrCondOpLowering, CIRTernaryOpLowering, CIRYieldOpLowering, CIRCosOpLowering, CIRGlobalOpLowering, CIRGetGlobalOpLowering, CIRCastOpLowering, - CIRPtrStrideOpLowering, CIRSqrtOpLowering, CIRCeilOpLowering, - CIRExp2OpLowering, CIRExpOpLowering, CIRFAbsOpLowering, - CIRAbsOpLowering, CIRFloorOpLowering, CIRLog10OpLowering, - CIRLog2OpLowering, CIRLogOpLowering, CIRRoundOpLowering, - CIRPtrStrideOpLowering, CIRSinOpLowering, CIRShiftOpLowering, - CIRBitClzOpLowering, CIRBitCtzOpLowering, CIRBitPopcountOpLowering, - CIRBitClrsbOpLowering, CIRBitFfsOpLowering, CIRBitParityOpLowering, - CIRIfOpLowering, CIRVectorCreateLowering, CIRVectorInsertLowering, - CIRVectorExtractLowering, CIRVectorCmpOpLowering, CIRACosOpLowering, - CIRASinOpLowering, CIRUnreachableOpLowering, CIRTanOpLowering, - CIRTrapOpLowering>(converter, patterns.getContext()); + CIRPtrStrideOpLowering, CIRGetElementOpLowering, CIRSqrtOpLowering, + CIRCeilOpLowering, CIRExp2OpLowering, CIRExpOpLowering, + CIRFAbsOpLowering, CIRAbsOpLowering, CIRFloorOpLowering, + CIRLog10OpLowering, CIRLog2OpLowering, CIRLogOpLowering, + CIRRoundOpLowering, CIRPtrStrideOpLowering, CIRSinOpLowering, + CIRShiftOpLowering, CIRBitClzOpLowering, CIRBitCtzOpLowering, + CIRBitPopcountOpLowering, CIRBitClrsbOpLowering, CIRBitFfsOpLowering, + CIRBitParityOpLowering, CIRIfOpLowering, CIRVectorCreateLowering, + CIRVectorInsertLowering, CIRVectorExtractLowering, + CIRVectorCmpOpLowering, CIRACosOpLowering, CIRASinOpLowering, + CIRUnreachableOpLowering, CIRTanOpLowering, CIRTrapOpLowering>( + converter, patterns.getContext()); } static mlir::TypeConverter prepareTypeConverter() { diff --git a/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c b/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c index 0fc82e8ef65c..0fb0ae539061 100644 --- a/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c +++ b/clang/test/CIR/CallConvLowering/AArch64/aarch64-cc-structs.c @@ -399,8 +399,7 @@ void qux(void) { // CHECK: %[[#V1:]] = cir.alloca !u64i, !cir.ptr, ["tmp"] // CHECK: %[[#V2:]] = cir.get_global @g : !cir.ptr> // CHECK: %[[#V3:]] = cir.const #cir.int<1> : !s32i -// CHECK: %[[#V4:]] = cir.cast(array_to_ptrdecay, %[[#V2]] : !cir.ptr>), !cir.ptr -// CHECK: %[[#V5:]] = cir.ptr_stride(%[[#V4]] : !cir.ptr, %[[#V3]] : !s32i), !cir.ptr +// CHECK: %[[#V5:]] = cir.get_element %[[#V2]][%[[#V3]]] : (!cir.ptr>, !s32i) -> !cir.ptr // CHECK: cir.store{{.*}} %[[#V5]], %[[#V0]] : !cir.ptr, !cir.ptr> // CHECK: %[[#V6:]] = cir.load deref{{.*}} %[[#V0]] : !cir.ptr>, !cir.ptr // CHECK: %[[#V7:]] = cir.cast(bitcast, %[[#V6]] : !cir.ptr), !cir.ptr diff --git a/clang/test/CIR/CodeGen/array.c b/clang/test/CIR/CodeGen/array.c index ae2d9900448a..01edf2f34ab6 100644 --- a/clang/test/CIR/CodeGen/array.c +++ b/clang/test/CIR/CodeGen/array.c @@ -8,7 +8,7 @@ struct S { // CHECK: cir.global external @arr = #cir.const_array<[#cir.const_record<{#cir.int<1> : !s32i}> : !rec_S, #cir.zero : !rec_S, #cir.zero : !rec_S]> : !cir.array int a[4]; -// CHECK: cir.global external @a = #cir.zero : !cir.array +// CHECK: cir.global external @a = #cir.zero : !cir.array // Should create a pointer to a complete array. int (*complete_ptr_a)[4] = &a; @@ -27,6 +27,5 @@ void useFoo(int i) { // CHECK: @useFoo // CHECK: %[[#V2:]] = cir.get_global @foo : !cir.ptr> // CHECK: %[[#V3:]] = cir.load{{.*}} %{{.+}} : !cir.ptr, !s32i -// CHECK: %[[#V4:]] = cir.cast(array_to_ptrdecay, %[[#V2]] : !cir.ptr>), !cir.ptr -// CHECK: %[[#V5:]] = cir.ptr_stride(%[[#V4]] : !cir.ptr, %[[#V3]] : !s32i), !cir.ptr -// CHECK: cir.store{{.*}} %{{.+}}, %[[#V5]] : !s32i, !cir.ptr +// CHECK: %[[#V4:]] = cir.get_element %[[#V2]][%[[#V3]]] : (!cir.ptr>, !s32i) -> !cir.ptr +// CHECK: cir.store{{.*}} %{{.+}}, %[[#V4]] : !s32i, !cir.ptr diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp index f62a8ff49b13..2bebbe67e04e 100644 --- a/clang/test/CIR/CodeGen/array.cpp +++ b/clang/test/CIR/CodeGen/array.cpp @@ -17,9 +17,8 @@ void a1() { // CHECK-NEXT: %0 = cir.alloca !cir.array, !cir.ptr>, ["a"] {alignment = 16 : i64} // CHECK-NEXT: %1 = cir.const #cir.int<1> : !s32i // CHECK-NEXT: %2 = cir.const #cir.int<0> : !s32i -// CHECK-NEXT: %3 = cir.cast(array_to_ptrdecay, %0 : !cir.ptr>), !cir.ptr -// CHECK-NEXT: %4 = cir.ptr_stride(%3 : !cir.ptr, %2 : !s32i), !cir.ptr -// CHECK-NEXT: cir.store{{.*}} %1, %4 : !s32i, !cir.ptr +// CHECK-NEXT: %3 = cir.get_element %0[%2] : (!cir.ptr>, !s32i) -> !cir.ptr +// CHECK-NEXT: cir.store{{.*}} %1, %3 : !s32i, !cir.ptr int *a2() { int a[4]; @@ -30,11 +29,10 @@ int *a2() { // CHECK-NEXT: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["__retval"] {alignment = 8 : i64} // CHECK-NEXT: %1 = cir.alloca !cir.array, !cir.ptr>, ["a"] {alignment = 16 : i64} // CHECK-NEXT: %2 = cir.const #cir.int<0> : !s32i -// CHECK-NEXT: %3 = cir.cast(array_to_ptrdecay, %1 : !cir.ptr>), !cir.ptr -// CHECK-NEXT: %4 = cir.ptr_stride(%3 : !cir.ptr, %2 : !s32i), !cir.ptr -// CHECK-NEXT: cir.store{{.*}} %4, %0 : !cir.ptr, !cir.ptr> -// CHECK-NEXT: %5 = cir.load{{.*}} %0 : !cir.ptr>, !cir.ptr -// CHECK-NEXT: cir.return %5 : !cir.ptr +// CHECK-NEXT: %3 = cir.get_element %1[%2] : (!cir.ptr>, !s32i) -> !cir.ptr +// CHECK-NEXT: cir.store{{.*}} %3, %0 : !cir.ptr, !cir.ptr> +// CHECK-NEXT: %4 = cir.load{{.*}} %0 : !cir.ptr>, !cir.ptr +// CHECK-NEXT: cir.return %4 : !cir.ptr void local_stringlit() { const char *s = "whatnow"; @@ -53,14 +51,12 @@ int multidim(int i, int j) { } // CHECK: %3 = cir.alloca !cir.array x 2>, !cir.ptr x 2>> -// Stride first dimension (stride = 2) +// Index first dimension (index = 2) // CHECK: %4 = cir.load{{.*}} %{{.+}} : !cir.ptr, !s32i -// CHECK: %5 = cir.cast(array_to_ptrdecay, %3 : !cir.ptr x 2>>), !cir.ptr> -// CHECK: %6 = cir.ptr_stride(%5 : !cir.ptr>, %4 : !s32i), !cir.ptr> -// Stride second dimension (stride = 1) -// CHECK: %7 = cir.load{{.*}} %{{.+}} : !cir.ptr, !s32i -// CHECK: %8 = cir.cast(array_to_ptrdecay, %6 : !cir.ptr>), !cir.ptr -// CHECK: %9 = cir.ptr_stride(%8 : !cir.ptr, %7 : !s32i), !cir.ptr +// CHECK: %5 = cir.get_element %3[%4] : (!cir.ptr x 2>>, !s32i) -> !cir.ptr> +// Index second dimension (index = 1) +// CHECK: %6 = cir.load{{.*}} %{{.+}} : !cir.ptr, !s32i +// CHECK: %7 = cir.get_element %5[%6] : (!cir.ptr>, !s32i) -> !cir.ptr // Should globally zero-initialize null arrays. int globalNullArr[] = {0, 0}; @@ -83,12 +79,11 @@ void testPointerDecaySubscriptAccess(int arr[]) { void testPointerDecayedArrayMultiDimSubscriptAccess(int arr[][3]) { // CHECK: cir.func dso_local @{{.+}}testPointerDecayedArrayMultiDimSubscriptAccess arr[1][2]; - // CHECK: %[[#V1:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>>, !cir.ptr> - // CHECK: %[[#V2:]] = cir.const #cir.int<1> : !s32i - // CHECK: %[[#V3:]] = cir.ptr_stride(%[[#V1]] : !cir.ptr>, %[[#V2]] : !s32i), !cir.ptr> - // CHECK: %[[#V4:]] = cir.const #cir.int<2> : !s32i - // CHECK: %[[#V5:]] = cir.cast(array_to_ptrdecay, %[[#V3]] : !cir.ptr>), !cir.ptr - // CHECK: cir.ptr_stride(%[[#V5]] : !cir.ptr, %[[#V4]] : !s32i), !cir.ptr + // CHECK: %[[#ARRAY:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>>, !cir.ptr> + // CHECK: %[[#ONE:]] = cir.const #cir.int<1> : !s32i + // CHECK: %[[#OUTER:]] = cir.ptr_stride(%[[#ARRAY]] : !cir.ptr>, %[[#ONE]] : !s32i), !cir.ptr> + // CHECK: %[[#TWO:]] = cir.const #cir.int<2> : !s32i + // CHECK: %[[#INNER:]] = cir.get_element %[[#OUTER]][%[[#TWO]]] : (!cir.ptr>, !s32i) -> !cir.ptr } void testArrayOfComplexType() { int _Complex a[4]; } diff --git a/clang/test/CIR/CodeGen/bitint.cpp b/clang/test/CIR/CodeGen/bitint.cpp index 999d3f747cbb..029e11a111ad 100644 --- a/clang/test/CIR/CodeGen/bitint.cpp +++ b/clang/test/CIR/CodeGen/bitint.cpp @@ -58,9 +58,8 @@ void Size1ExtIntParam(unsigned _BitInt(1) A) { // CHECK: cir.func dso_local @_Z16Size1ExtIntParamDU1_ // CHECK: %[[#A:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>, !cir.int // CHECK-NEXT: %[[#IDX:]] = cir.const #cir.int<2> : !s32i -// CHECK-NEXT: %[[#ARRAY:]] = cir.cast(array_to_ptrdecay, %1 : !cir.ptr x 5>>), !cir.ptr> -// CHECK-NEXT: %[[#PTR:]] = cir.ptr_stride(%[[#ARRAY]] : !cir.ptr>, %[[#IDX]] : !s32i), !cir.ptr> -// CHECK-NEXT: cir.store{{.*}} %[[#A]], %[[#PTR]] : !cir.int, !cir.ptr> +// CHECK-NEXT: %[[#ELEM:]] = cir.get_element %1[%[[#IDX]]] : (!cir.ptr x 5>>, !s32i) -> !cir.ptr> +// CHECK-NEXT: cir.store{{.*}} %[[#A]], %[[#ELEM]] : !cir.int, !cir.ptr> // CHECK: } struct S { diff --git a/clang/test/CIR/CodeGen/complex.c b/clang/test/CIR/CodeGen/complex.c index b4b6ef24fb39..dd43a0c25046 100644 --- a/clang/test/CIR/CodeGen/complex.c +++ b/clang/test/CIR/CodeGen/complex.c @@ -407,14 +407,12 @@ void complex_array_subscript() { // CHECK: %[[ARR:.*]] = cir.alloca !cir.array x 2>, !cir.ptr x 2>>, ["arr"] // CHECK: %[[RESULT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["r", init] // CHECK: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i -// CHECK: %[[ARR_PTR:.*]] = cir.cast(array_to_ptrdecay, %[[ARR]] : !cir.ptr x 2>>), !cir.ptr> -// CHECK: %[[RESULT_VAL:.*]] = cir.ptr_stride(%[[ARR_PTR]] : !cir.ptr>, %[[IDX]] : !s32i), !cir.ptr> +// CHECK: %[[RESULT_VAL:.*]] = cir.get_element %[[ARR]][%[[IDX]]] : (!cir.ptr>, !s32i) -> !cir.ptr> // CHECK: %[[TMP:.*]] = cir.load{{.*}} %[[RESULT_VAL]] : !cir.ptr>, !cir.complex // CHECK: cir.store{{.*}} %[[TMP]], %[[RESULT]] : !cir.complex, !cir.ptr> // LLVM: %[[ARR:.*]] = alloca [2 x { i32, i32 }], i64 1, align 16 // LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4 -// LLVM: %[[ARR_PTR:.*]] = getelementptr { i32, i32 }, ptr %[[ARR]], i32 0 -// LLVM: %[[RESULT_VAL:.*]] = getelementptr { i32, i32 }, ptr %[[ARR_PTR]], i64 1 +// LLVM: %[[RESULT_VAL:.*]] = getelementptr [2 x { i32, i32 }], ptr %[[ARR]], i32 0, i64 1 // LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[RESULT_VAL]], align 8 // LLVM: store { i32, i32 } %[[TMP]], ptr %[[RESULT]], align 4 diff --git a/clang/test/CIR/CodeGen/struct.c b/clang/test/CIR/CodeGen/struct.c index fd223abb2e27..ca13ffe0a390 100644 --- a/clang/test/CIR/CodeGen/struct.c +++ b/clang/test/CIR/CodeGen/struct.c @@ -88,8 +88,7 @@ struct Bar shouldGenerateAndAccessStructArrays(void) { } // CHECK-DAG: cir.func dso_local @shouldGenerateAndAccessStructArrays // CHECK-DAG: %[[#STRIDE:]] = cir.const #cir.int<0> : !s32i -// CHECK-DAG: %[[#DARR:]] = cir.cast(array_to_ptrdecay, %{{.+}} : !cir.ptr>), !cir.ptr -// CHECK-DAG: %[[#ELT:]] = cir.ptr_stride(%[[#DARR]] : !cir.ptr, %[[#STRIDE]] : !s32i), !cir.ptr +// CHECK-DAG: %[[#ELT:]] = cir.get_element %{{.+}}[%[[#STRIDE]]] : (!cir.ptr>, !s32i) -> !cir.ptr // CHECK-DAG: cir.copy %[[#ELT]] to %{{.+}} : !cir.ptr // CHECK-DAG: cir.func dso_local @local_decl diff --git a/clang/test/CIR/Lowering/ThroughMLIR/array.c b/clang/test/CIR/Lowering/ThroughMLIR/array.c index b02b07c9cfd8..3962968ca0c5 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/array.c +++ b/clang/test/CIR/Lowering/ThroughMLIR/array.c @@ -6,43 +6,40 @@ int test_array1() { // CIR-LABEL: cir.func {{.*}} @test_array1 // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array, !cir.ptr>, ["a"] {alignment = 4 : i64} - // CIR: %{{.*}} = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr>), !cir.ptr + // CIR: %{{.*}} = cir.get_element %[[ARRAY]][{{.*}}] : (!cir.ptr>, !s32i) -> !cir.ptr // MLIR-LABEL: func @test_array1 // MLIR: %{{.*}} = memref.alloca() {alignment = 4 : i64} : memref // MLIR: %[[ARRAY:.*]] = memref.alloca() {alignment = 4 : i64} : memref<3xi32> // MLIR: %{{.*}} = memref.load %[[ARRAY]][%{{.*}}] : memref<3xi32> int a[3]; - return a[1]; + return a[1]; } int test_array2() { // CIR-LABEL: cir.func {{.*}} @test_array2 // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array x 3>, !cir.ptr x 3>>, ["a"] {alignment = 16 : i64} - // CIR: %{{.*}} = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr x 3>>), !cir.ptr> - // CIR: %{{.*}} = cir.cast(array_to_ptrdecay, %{{.*}} : !cir.ptr>), !cir.ptr + // CIR: %{{.*}} = cir.get_element %[[ARRAY]][%{{.*}}] : (!cir.ptr x 3>>, !s32i) -> !cir.ptr> + // CIR: %{{.*}} = cir.get_element %{{.*}}[%{{.*}}] : (!cir.ptr>, !s32i) -> !cir.ptr // MLIR-LABEL: func @test_array2 // MLIR: %{{.*}} = memref.alloca() {alignment = 4 : i64} : memref // MLIR: %[[ARRAY:.*]] = memref.alloca() {alignment = 16 : i64} : memref<3x4xi32> // MLIR: %{{.*}} = memref.load %[[ARRAY]][%{{.*}}, %{{.*}}] : memref<3x4xi32> int a[3][4]; - return a[1][2]; + return a[1][2]; } int test_array3() { // CIR-LABEL: cir.func {{.*}} @test_array3() // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array, !cir.ptr>, ["a"] {alignment = 4 : i64} - // CIR: %[[PTRDECAY1:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr>), !cir.ptr - // CIR: %[[PTRSTRIDE1:.*]] = cir.ptr_stride(%[[PTRDECAY1]] : !cir.ptr, {{.*}} : !s32i), !cir.ptr - // CIR: {{.*}} = cir.load align(4) %[[PTRSTRIDE1]] : !cir.ptr, !s32i - // CIR: %[[PTRDECAY2:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr>), !cir.ptr - // CIR: %[[PTRSTRIDE2:.*]] = cir.ptr_stride(%[[PTRDECAY2]] : !cir.ptr, {{.*}} : !s32i), !cir.ptr - // CIR: %{{.*}} = cir.load align(4) %[[PTRSTRIDE2]] : !cir.ptr, !s32i - // CIR: cir.store align(4) {{.*}}, %[[PTRSTRIDE2]] : !s32i, !cir.ptr - // CIR: %[[PTRDECAY3:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr>), !cir.ptr - // CIR: %[[PTRSTRIDE3:.*]] = cir.ptr_stride(%[[PTRDECAY3]] : !cir.ptr, {{.*}} : !s32i), !cir.ptr - // CIR: %{{.*}} = cir.load align(4) %[[PTRSTRIDE3]] : !cir.ptr, !s32i + // CIR: %[[ELEM1:.*]] = cir.get_element %[[ARRAY]][{{.*}}] : (!cir.ptr>, !s32i) -> !cir.ptr + // CIR: {{.*}} = cir.load align(4) %[[ELEM1]] : !cir.ptr, !s32i + // CIR: %[[ELEM2:.*]] = cir.get_element %[[ARRAY]][{{.*}}] : (!cir.ptr>, !s32i) -> !cir.ptr + // CIR: %{{.*}} = cir.load align(4) %[[ELEM2]] : !cir.ptr, !s32i + // CIR: cir.store align(4) {{.*}}, %[[ELEM2]] : !s32i, !cir.ptr + // CIR: %[[ELEM3:.*]] = cir.get_element %[[ARRAY]][{{.*}}] : (!cir.ptr>, !s32i) -> !cir.ptr + // CIR: %{{.*}} = cir.load align(4) %[[ELEM3]] : !cir.ptr, !s32i // MLIR-LABEL: func @test_array3 // MLIR: %{{.*}} = memref.alloca() {alignment = 4 : i64} : memref @@ -50,11 +47,11 @@ int test_array3() { // MLIR: %[[IDX1:.*]] = arith.index_cast %{{.*}} : i32 to index // MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX1]]] : memref<3xi32> // MLIR: %[[IDX2:.*]] = arith.index_cast %{{.*}} : i32 to index - // MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX2]]] : memref<3xi32> - // MLIR: memref.store %{{.*}}, %[[ARRAY]][%[[IDX2]]] : memref<3xi32> + // MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX2]]] : memref<3xi32> + // MLIR: memref.store %{{.*}}, %[[ARRAY]][%[[IDX2]]] : memref<3xi32> // MLIR: %[[IDX3:.*]] = arith.index_cast %{{.*}} : i32 to index - // MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX3]]] : memref<3xi32> + // MLIR: %{{.*}} = memref.load %[[ARRAY]][%[[IDX3]]] : memref<3xi32> int a[3]; a[0] += a[2]; - return a[1]; + return a[1]; }