[CIR] Add 'get element' for array index ops (#172897)

This is a refactor/upstream/etc of:
https://github.com/llvm/clangir/pull/1748

This modifies our array-index operations to use a specific operation
(GetElementOp). According to the original patch commit message, this
replaces nearly 50% of ptr_stride operations in single source tests!
This commit is contained in:
Erich Keane 2025-12-19 19:39:08 -08:00 committed by GitHub
parent 59da50c771
commit a95a303a54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 187 additions and 89 deletions

View File

@ -2724,6 +2724,63 @@ def CIR_GetMemberOp : CIR_Op<"get_member"> {
let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
// GetElementOp
//===----------------------------------------------------------------------===//
def CIR_GetElementOp : CIR_Op<"get_element", [
TypesMatchWith<
"type of 'result' matches element type of 'base'", "base", "result",
"cir::PointerType::get(mlir::cast<cir::ArrayType>(mlir::cast<cir::"
"PointerType>($_self).getPointee()).getElementType())">
]> {
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<s, 32>
!arr_ty = !cir.array<!s32i x 4>
// Get the address of the element at index 1.
%elem_1 = cir.get_element %0[1 : !s32i] : !cir.ptr<!array_ty> -> !cir.ptr<!s32i>
// Get the address of the element at index %i.
%i = ...
%elem_i = cir.get_element %0[%i : !s32i] : !cir.ptr<!array_ty> -> !cir.ptr<!s32i>
```
}];
let arguments = (ins
Arg<CIR_PtrToArray, "the base address of the array ">:$base,
Arg<CIR_AnyFundamentalIntType, "the index of the element">:$index
);
let results = (outs CIR_PointerType : $result);
let assemblyFormat = [{
$base`[` $index `:` type($index) `]` attr-dict
`:` qualified(type($base)) `->` qualified(type($result))
}];
let extraClassDeclaration = [{
// Get the type of the element of the array.
mlir::Type getElementType() {
return getType().getPointee();
}
cir::PointerType getBaseType() {
return mlir::cast<cir::PointerType>(getBase().getType());
}
}];
}
//===----------------------------------------------------------------------===//
// FuncOp
//===----------------------------------------------------------------------===//

View File

@ -36,6 +36,19 @@ mlir::Value CIRGenBuilderTy::getArrayElement(mlir::Location arrayLocBegin,
mlir::Value arrayPtr,
mlir::Type eltTy, mlir::Value idx,
bool shouldDecay) {
auto arrayPtrTy = mlir::dyn_cast<cir::PointerType>(arrayPtr.getType());
assert(arrayPtrTy && "expected pointer type");
// If the array pointer is not decayed, emit a GetElementOp.
auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayPtrTy.getPointee());
if (shouldDecay && arrayTy && arrayTy == eltTy) {
auto eltPtrTy =
getPointerTo(arrayTy.getElementType(), arrayPtrTy.getAddrSpace());
return cir::GetElementOp::create(*this, arrayLocEnd, eltPtrTy, arrayPtr,
idx);
}
// If we don't have sufficient type information, emit a PtrStrideOp.
mlir::Value basePtr = arrayPtr;
if (shouldDecay)
basePtr = maybeBuildArrayDecay(arrayLocBegin, arrayPtr, eltTy);

View File

@ -2536,7 +2536,6 @@ LogicalResult cir::GetMemberOp::verify() {
return mlir::success();
}
//===----------------------------------------------------------------------===//
// VecCreateOp
//===----------------------------------------------------------------------===//

View File

@ -1347,6 +1347,55 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
return mlir::success();
}
static mlir::Value convertToIndexTy(mlir::ConversionPatternRewriter &rewriter,
mlir::ModuleOp mod, mlir::Value index,
mlir::Type baseTy, cir::IntType strideTy) {
mlir::Operation *indexOp = index.getDefiningOp();
if (!indexOp)
return index;
auto indexType = mlir::cast<mlir::IntegerType>(index.getType());
mlir::DataLayout llvmLayout(mod);
std::optional<uint64_t> layoutWidth = llvmLayout.getTypeIndexBitwidth(baseTy);
// If there is no change in width, don't do anything.
if (!layoutWidth || *layoutWidth == indexType.getWidth())
return index;
// 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<mlir::LLVM::SubOp>(indexOp);
bool rewriteSub = false;
if (sub) {
if (auto lhsConst =
dyn_cast<mlir::LLVM::ConstantOp>(sub.getLhs().getDefiningOp())) {
auto lhsConstInt = mlir::dyn_cast<mlir::IntegerAttr>(lhsConst.getValue());
if (lhsConstInt && lhsConstInt.getValue() == 0) {
index = sub.getRhs();
rewriteSub = true;
}
}
}
auto llvmDstType = rewriter.getIntegerType(*layoutWidth);
bool isUnsigned = strideTy && strideTy.isUnsigned();
index = getLLVMIntCast(rewriter, index, llvmDstType, isUnsigned,
indexType.getWidth(), *layoutWidth);
if (rewriteSub) {
index = mlir::LLVM::SubOp::create(
rewriter, index.getLoc(),
mlir::LLVM::ConstantOp::create(rewriter, index.getLoc(),
index.getType(), 0),
index);
// TODO: ensure sub is trivially dead now.
rewriter.eraseOp(sub);
}
return index;
}
mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@ -1356,7 +1405,6 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
mlir::Type elementTy =
convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementType());
mlir::MLIRContext *ctx = elementTy.getContext();
// void and function types doesn't really have a layout to use in GEPs,
// make it i8 instead.
@ -1366,45 +1414,52 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
mlir::IntegerType::Signless);
// Zero-extend, sign-extend or trunc the pointer value.
mlir::Value index = adaptor.getStride();
const unsigned width =
mlir::cast<mlir::IntegerType>(index.getType()).getWidth();
const std::optional<std::uint64_t> layoutWidth =
dataLayout.getTypeIndexBitwidth(adaptor.getBase().getType());
mlir::Operation *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".
const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp);
auto unary = ptrStrideOp.getStride().getDefiningOp<cir::UnaryOp>();
bool rewriteSub =
unary && unary.getKind() == cir::UnaryOpKind::Minus && sub;
if (rewriteSub)
index = indexOp->getOperand(1);
// Handle the cast
const 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 = mlir::LLVM::SubOp::create(
rewriter, index.getLoc(), index.getType(),
mlir::LLVM::ConstantOp::create(rewriter, index.getLoc(),
index.getType(), 0),
index);
rewriter.eraseOp(sub);
}
}
index = convertToIndexTy(
rewriter, ptrStrideOp->getParentOfType<mlir::ModuleOp>(), index,
adaptor.getBase().getType(),
dyn_cast<cir::IntType>(ptrStrideOp.getOperand(1).getType()));
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
ptrStrideOp, resultTy, elementTy, adaptor.getBase(), index);
return mlir::success();
}
mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite(
cir::GetElementOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
if (auto arrayTy =
mlir::dyn_cast<cir::ArrayType>(op.getBaseType().getPointee())) {
const mlir::TypeConverter *converter = getTypeConverter();
const mlir::Type llArrayTy = converter->convertType(arrayTy);
const mlir::Type llResultTy = converter->convertType(op.getType());
mlir::Type elementTy =
convertTypeForMemory(*converter, dataLayout, op.getElementType());
// void and function types don't really have a layout to use in GEPs,
// make it i8 instead.
if (mlir::isa<mlir::LLVM::LLVMVoidType>(elementTy) ||
mlir::isa<mlir::LLVM::LLVMFunctionType>(elementTy))
elementTy = rewriter.getIntegerType(8);
mlir::Value index = adaptor.getIndex();
index =
convertToIndexTy(rewriter, op->getParentOfType<mlir::ModuleOp>(), index,
adaptor.getBase().getType(),
dyn_cast<cir::IntType>(op.getOperand(1).getType()));
// 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.
std::array<mlir::LLVM::GEPArg, 2> offset{0, index};
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, llResultTy, llArrayTy,
adaptor.getBase(), offset);
return mlir::success();
}
op.emitError() << "NYI: GetElementOp lowering to LLVM for non-array";
return mlir::failure();
}
mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {

View File

@ -113,13 +113,11 @@ void func() {
// CIR: %[[INIT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e", init]
// CIR: %[[INIT_2:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["e2", init]
// CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[IDX]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.get_element %[[ARR]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
// CIR" cir.store %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[IDX]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.get_element %[[ARR]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
// CIR" cir.store %[[TMP]], %[[INIT_2]] : !s32i, !cir.ptr<!s32i>
@ -127,12 +125,10 @@ void func() {
// LLVM-NEXT: %[[ARR:.*]] = alloca [10 x i32], i64 1, align 16
// LLVM-NEXT: %[[INIT:.*]] = alloca i32, i64 1, align 4
// LLVM-NEXT: %[[INIT_2:.*]] = alloca i32, i64 1, align 4
// LLVM-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 0
// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr [10 x i32], ptr %[[ARR]], i32 0, i64 0
// LLVM-NEXT: %[[TMP_1:.*]] = load i32, ptr %[[ELE_PTR]], align 16
// LLVM-NEXT: store i32 %[[TMP_1]], ptr %[[INIT]], align 4
// LLVM-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
// LLVM-NEXT: %[[ELE_PTR:.*]] = getelementptr [10 x i32], ptr %[[ARR]], i32 0, i64 1
// LLVM-NEXT: %[[TMP_2:.*]] = load i32, ptr %[[ELE_PTR]], align 4
// LLVM-NEXT: store i32 %[[TMP_2]], ptr %[[INIT_2]], align 4
@ -176,8 +172,7 @@ void func3() {
// CIR: %[[IDX_V:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.store{{.*}} %[[IDX_V]], %[[IDX]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP_IDX:.*]] = cir.load{{.*}} %[[IDX]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[TMP_IDX]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.get_element %[[ARR]][%[[TMP_IDX]] : !s32i] : !cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_TMP:.*]] = cir.load{{.*}} %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store{{.*}} %[[ELE_TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
@ -188,9 +183,8 @@ void func3() {
// LLVM: store [2 x i32] [i32 5, i32 6], ptr %[[ARR]], align 4
// LLVM: store i32 1, ptr %[[IDX]], align 4
// LLVM: %[[TMP1:.*]] = load i32, ptr %[[IDX]], align 4
// LLVM: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR]], i32 0
// LLVM: %[[IDX_I64:.*]] = sext i32 %[[TMP1]] to i64
// LLVM: %[[ELE:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 %[[IDX_I64]]
// LLVM: %[[ELE:.*]] = getelementptr [2 x i32], ptr %[[ARR]], i32 0, i64 %[[IDX_I64]]
// LLVM: %[[TMP2:.*]] = load i32, ptr %[[ELE]], align 4
// LLVM: store i32 %[[TMP2]], ptr %[[INIT]], align 4
@ -216,10 +210,8 @@ void func4() {
// CIR: cir.store{{.*}} %[[CONST]], %[[ARR]] : !cir.array<!cir.array<!s32i x 1> x 2>, !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>>
// CIR: %[[IDX:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>>
// CIR: %[[ARR_1:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[IDX_1]] : (!cir.ptr<!cir.array<!s32i x 1>>, !s32i) -> !cir.ptr<!cir.array<!s32i x 1>>
// CIR: %[[ARR_1_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR_1]] : !cir.ptr<!cir.array<!s32i x 1>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_0:.*]] = cir.ptr_stride %[[ARR_1_PTR]], %[[IDX]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ARR_1:.*]] = cir.get_element %[[ARR]][%[[IDX_1]] : !s32i] : !cir.ptr<!cir.array<!cir.array<!s32i x 1> x 2>> -> !cir.ptr<!cir.array<!s32i x 1>>
// CIR: %[[ELE_0:.*]] = cir.get_element %[[ARR_1]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s32i x 1>> -> !cir.ptr<!s32i>
// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[ELE_0]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store{{.*}} %[[TMP]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
@ -227,10 +219,8 @@ void func4() {
// LLVM: %[[ARR:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
// LLVM: %[[INIT:.*]] = alloca i32, i64 1, align 4
// LLVM: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] [i32 6]], ptr %[[ARR]], align 4
// LLVM: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR]], i32 0
// LLVM: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
// LLVM: %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
// LLVM: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_1_0]], i64 0
// LLVM: %[[ARR_1:.*]] = getelementptr [2 x [1 x i32]], ptr %[[ARR]], i32 0, i64 1
// LLVM: %[[ELE_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1]], i32 0, i64 0
// LLVM: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
// LLVM: store i32 %[[TMP]], ptr %[[INIT]], align 4
@ -367,8 +357,7 @@ void func9(int arr[10][5]) {
// CIR: %[[IDX_1:.*]] = cir.const #cir.int<1> : !s32i
// CIR: %[[TMP_1:.*]] = cir.load{{.*}} %[[ARR]] : !cir.ptr<!cir.ptr<!cir.array<!s32i x 5>>>, !cir.ptr<!cir.array<!s32i x 5>>
// CIR: %[[ARR_1:.*]] = cir.ptr_stride %[[TMP_1]], %[[IDX_1]] : (!cir.ptr<!cir.array<!s32i x 5>>, !s32i) -> !cir.ptr<!cir.array<!s32i x 5>>
// CIR: %[[ARR_1_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR_1]] : !cir.ptr<!cir.array<!s32i x 5>> -> !cir.ptr<!s32i>
// CIR: %[[ARR_1_2:.*]] = cir.ptr_stride %[[ARR_1_PTR]], %[[IDX]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ARR_1_2:.*]] = cir.get_element %[[ARR_1]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s32i x 5>> -> !cir.ptr<!s32i>
// CIR: %[[TMP_2:.*]] = cir.load{{.*}} %[[ARR_1_2]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store{{.*}} %[[TMP_2]], %[[INIT]] : !s32i, !cir.ptr<!s32i>
@ -378,8 +367,7 @@ void func9(int arr[10][5]) {
// LLVM: store ptr %[[ARG]], ptr %[[ARR]], align 8
// LLVM: %[[TMP_1:.*]] = load ptr, ptr %[[ARR]], align 8
// LLVM: %[[ARR_1:.*]] = getelementptr [5 x i32], ptr %[[TMP_1]], i64 1
// LLVM: %[[ARR_1_PTR:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
// LLVM: %[[ARR_1_2:.*]] = getelementptr i32, ptr %[[ARR_1_PTR]], i64 2
// LLVM: %[[ARR_1_2:.*]] = getelementptr [5 x i32], ptr %[[ARR_1]], i32 0, i64 2
// LLVM: %[[TMP_2:.*]] = load i32, ptr %[[ARR_1_2]], align 4
// LLVM: store i32 %[[TMP_2]], ptr %[[INIT]], align 4

View File

@ -125,8 +125,7 @@ int ignore_result_assign() {
// CIR: %[[VAL_0:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[VAL_5:.*]] = cir.const #cir.int<5> : !s32i
// CIR: cir.store{{.*}} %[[VAL_5]], %[[I]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[ARR_DECAY:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[ARR_ELEM:.*]] = cir.ptr_stride %[[ARR_DECAY]], %[[VAL_5]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ARR_ELEM:.*]] = cir.get_element %[[ARR]][%[[VAL_5]] : !s32i] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
// CIR: %[[ARR_LOAD:.*]] = cir.load{{.*}} %[[ARR_ELEM]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.store{{.*}} %[[ARR_LOAD]], %[[J]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
@ -157,9 +156,8 @@ int ignore_result_assign() {
// LLVM: store i32 123, ptr %[[I_PTR]]
// LLVM: store i32 123, ptr %[[J_PTR]]
// LLVM: store i32 5, ptr %[[I_PTR]]
// LLVM: %[[GEP1:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
// LLVM: %[[GEP2:.*]] = getelementptr i32, ptr %[[GEP1]], i64 5
// LLVM: %[[ARR_VAL:.*]] = load i32, ptr %[[GEP2]]
// LLVM: %[[GEP:.*]] = getelementptr [10 x i32], ptr %[[ARR_PTR]], i32 0, i64 5
// LLVM: %[[ARR_VAL:.*]] = load i32, ptr %[[GEP]]
// LLVM: store i32 %[[ARR_VAL]], ptr %[[J_PTR]]
// LLVM: store ptr null, ptr %[[Q_PTR]]
// LLVM: br label

View File

@ -612,15 +612,13 @@ void foo24() {
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!cir.complex<!s32i> x 2>, !cir.ptr<!cir.array<!cir.complex<!s32i> x 2>>, ["arr"]
// CIR: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["r", init]
// CIR: %[[IDX:.*]] = cir.const #cir.int<1> : !s32i
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!cir.complex<!s32i> x 2>> -> !cir.ptr<!cir.complex<!s32i>>
// CIR: %[[RESULT_VAL:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[IDX]] : (!cir.ptr<!cir.complex<!s32i>>, !s32i) -> !cir.ptr<!cir.complex<!s32i>>
// CIR: %[[RESULT_VAL:.*]] = cir.get_element %[[ARR]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!cir.complex<!s32i> x 2>> -> !cir.ptr<!cir.complex<!s32i>>
// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[RESULT_VAL]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
// CIR: cir.store{{.*}} %[[TMP]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
// 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

View File

@ -177,16 +177,14 @@ void f3(union U3 u) {
// CIR-NEXT: %[[ZERO_CHAR:.*]] = cir.cast integral %[[ZERO]] : !s32i -> !s8i
// CIR-NEXT: %[[IDX:.*]] = cir.const #cir.int<2> : !s32i
// CIR-NEXT: %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : !cir.ptr<!rec_U3> -> !cir.ptr<!cir.array<!s8i x 5>>
// CIR-NEXT: %[[C_DECAY:.*]] = cir.cast array_to_ptrdecay %[[C_PTR]] : !cir.ptr<!cir.array<!s8i x 5>> -> !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.ptr_stride %[[C_DECAY]], %[[IDX]] : (!cir.ptr<!s8i>, !s32i) -> !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.get_element %[[C_PTR]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s8i x 5>> -> !cir.ptr<!s8i>
// CIR-NEXT: cir.store{{.*}} %[[ZERO_CHAR]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @f3(%union.U3 %[[ARG:.*]])
// LLVM-NEXT: %[[U:.*]] = alloca %union.U3, i64 1, align 1
// LLVM-NEXT: store %union.U3 %[[ARG]], ptr %[[U]], align 1
// LLVM-NEXT: %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 2
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr [5 x i8], ptr %[[U]], i32 0, i64 2
// LLVM-NEXT: store i8 0, ptr %[[ELEM_PTR]], align 1
// LLVM-NEXT: ret void
@ -209,16 +207,14 @@ void f5(union U4 u) {
// CIR-NEXT: %[[CHAR_CAST:.*]] = cir.cast integral %[[CHAR_VAL]] : !s32i -> !s8i
// CIR-NEXT: %[[IDX:.*]] = cir.const #cir.int<4> : !s32i
// CIR-NEXT: %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : !cir.ptr<!rec_U4> -> !cir.ptr<!cir.array<!s8i x 5>>
// CIR-NEXT: %[[C_DECAY:.*]] = cir.cast array_to_ptrdecay %[[C_PTR]] : !cir.ptr<!cir.array<!s8i x 5>> -> !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.ptr_stride %[[C_DECAY]], %[[IDX]] : (!cir.ptr<!s8i>, !s32i) -> !cir.ptr<!s8i>
// CIR-NEXT: %[[ELEM_PTR:.*]] = cir.get_element %[[C_PTR]][%[[IDX]] : !s32i] : !cir.ptr<!cir.array<!s8i x 5>> -> !cir.ptr<!s8i>
// CIR-NEXT: cir.store{{.*}} %[[CHAR_CAST]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
// CIR-NEXT: cir.return
// LLVM: define{{.*}} void @f5(%union.U4 %[[ARG:.*]])
// LLVM-NEXT: %[[U:.*]] = alloca %union.U4, i64 1, align 4
// LLVM-NEXT: store %union.U4 %[[ARG]], ptr %[[U]], align 4
// LLVM-NEXT: %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 4
// LLVM-NEXT: %[[ELEM_PTR:.*]] = getelementptr [5 x i8], ptr %[[U]], i32 0, i64 4
// LLVM-NEXT: store i8 65, ptr %[[ELEM_PTR]], align 4
// LLVM-NEXT: ret void

View File

@ -168,8 +168,7 @@ int test6(void) {
// CIR: cir.func {{.*}} @test6() -> !s32i
// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
// CIR: %[[ARR:.*]] = cir.get_global @arr : !cir.ptr<!cir.array<!s32i x 3>>
// CIR: %[[ARR_PTR:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 3>> -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.ptr_stride %[[ARR_PTR]], %[[TWO]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
// CIR: %[[ELE_PTR:.*]] = cir.get_element %[[ARR]][%[[TWO]] : !s32i] : !cir.ptr<!cir.array<!s32i x 3>> -> !cir.ptr<!s32i>
// CIR: %[[ELE:.*]] = cir.load{{.*}} %[[ELE_PTR]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[IS_CONSTANT:.*]] = cir.is_constant %[[ELE]] : !s32i -> !cir.bool

View File

@ -1088,9 +1088,8 @@ void copy_member_of_array_element_member() {
for(int i = 0; i < 5; ++i);
// CHECK-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
// CHECK-NEXT: %[[GETINNER:.*]] = cir.get_member %[[OUTER]][0] {name = "inner"} : !cir.ptr<!rec_OuterTy> -> !cir.ptr<!cir.array<!rec_InnerTy x 4>>
// CHECK-NEXT: %[[INNERDECAY:.*]] = cir.cast array_to_ptrdecay %[[GETINNER]] : !cir.ptr<!cir.array<!rec_InnerTy x 4>> -> !cir.ptr<!rec_InnerTy>
// CHECK-NEXT: %[[STRIDE:.*]] = cir.ptr_stride %[[INNERDECAY]], %[[TWO]] : (!cir.ptr<!rec_InnerTy>, !s32i) -> !cir.ptr<!rec_InnerTy>
// CHECK-NEXT: %[[GETB:.*]] = cir.get_member %[[STRIDE]][1] {name = "b"} : !cir.ptr<!rec_InnerTy> -> !cir.ptr<!s32i>
// CHECK-NEXT: %[[GET_ELT:.*]] = cir.get_element %[[GETINNER]][%[[TWO]] : !s32i] : !cir.ptr<!cir.array<!rec_InnerTy x 4>> -> !cir.ptr<!rec_InnerTy>
// CHECK-NEXT: %[[GETB:.*]] = cir.get_member %[[GET_ELT]][1] {name = "b"} : !cir.ptr<!rec_InnerTy> -> !cir.ptr<!s32i>
// CHECK-NEXT: %[[COPYIN1:.*]] = acc.copyin varPtr(%[[GETB]] : !cir.ptr<!s32i>) -> !cir.ptr<!s32i> {dataClause = #acc<data_clause acc_copy>, name = "outer.inner[2].b"}
// CHECK-NEXT: acc.parallel combined(loop) dataOperands(%[[COPYIN1]] : !cir.ptr<!s32i>) {
// CHECK-NEXT: acc.loop combined(parallel) {

View File

@ -45,12 +45,10 @@ void func() {
// CHECK-NEXT: %[[ARR_ALLOCA:.*]] = alloca [10 x i32], i64 1, align 16
// CHECK-NEXT: %[[INIT:.*]] = alloca i32, i64 1, align 4
// CHECK-NEXT: %[[INIT_2:.*]] = alloca i32, i64 1, align 4
// CHECK-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 0
// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr [10 x i32], ptr %[[ARR_ALLOCA]], i32 0, i64 0
// CHECK-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 16
// CHECK-NEXT: store i32 %[[TMP]], ptr %[[INIT]], align 4
// CHECK-NEXT: %[[ARR_PTR:.*]] = getelementptr i32, ptr %[[ARR_ALLOCA]], i32 0
// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i64 1
// CHECK-NEXT: %[[ELE_PTR:.*]] = getelementptr [10 x i32], ptr %[[ARR_ALLOCA]], i32 0, i64 1
// CHECK-NEXT: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
// CHECK-NEXT: store i32 %[[TMP]], ptr %[[INIT_2]], align 4
@ -78,10 +76,8 @@ void func4() {
// CHECK: %[[ARR_ALLOCA:.*]] = alloca [2 x [1 x i32]], i64 1, align 4
// CHECK: %[[INIT:.*]] = alloca i32, i64 1, align 4
// CHECK: store [2 x [1 x i32]] {{\[}}[1 x i32] [i32 5], [1 x i32] [i32 6]], ptr %[[ARR_ALLOCA]], align 4
// CHECK: %[[ARR_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_ALLOCA]], i32 0
// CHECK: %[[ARR_1:.*]] = getelementptr [1 x i32], ptr %[[ARR_PTR]], i64 1
// CHECK: %[[ARR_1_0:.*]] = getelementptr i32, ptr %[[ARR_1]], i32 0
// CHECK: %[[ELE_PTR:.*]] = getelementptr i32, ptr %[[ARR_1_0]], i64 0
// CHECK: %[[ARR_1:.*]] = getelementptr [2 x [1 x i32]], ptr %[[ARR_ALLOCA]], i32 0, i64 1
// CHECK: %[[ELE_PTR:.*]] = getelementptr [1 x i32], ptr %[[ARR_1]], i32 0, i64 0
// CHECK: %[[TMP:.*]] = load i32, ptr %[[ELE_PTR]], align 4
// CHECK: store i32 %[[TMP]], ptr %[[INIT]], align 4