[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:
parent
59da50c771
commit
a95a303a54
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -2536,7 +2536,6 @@ LogicalResult cir::GetMemberOp::verify() {
|
||||
|
||||
return mlir::success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// VecCreateOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user