Normalize lowering of MemRef types
The RFC for unifying Linalg and Affine compilation passes into an end-to-end flow with a predictable ABI and linkage to external function calls raised the question of why we have variable sized descriptors for memrefs depending on whether they have static or dynamic dimensions (https://groups.google.com/a/tensorflow.org/forum/#!topic/mlir/MaL8m2nXuio).
This CL standardizes the ABI on the rank of the memrefs.
The LLVM struct for a memref becomes equivalent to:
```
template <typename Elem, size_t Rank>
struct {
Elem *ptr;
int64_t sizes[Rank];
};
```
PiperOrigin-RevId: 270947276
diff --git a/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp b/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp
index 48beba7..276043c 100644
--- a/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp
+++ b/examples/Linalg/Linalg1/lib/ConvertToLLVMDialect.cpp
@@ -181,8 +181,8 @@
// Helper function to obtain the size of the given `memref` along the
// dimension `dim`. For static dimensions, emits a constant; for dynamic
// dimensions, extracts the size from the memref descriptor.
- auto memrefSize = [int64Ty, pos, i64cst](MemRefType type, Value *memref,
- int dim) -> Value * {
+ auto memrefSize = [&rewriter, int64Ty, i64cst](
+ MemRefType type, Value *memref, int dim) -> Value * {
assert(dim < type.getRank());
if (type.getShape()[dim] != -1) {
return i64cst(type.getShape()[dim]);
@@ -191,14 +191,12 @@
for (int i = 0; i < dim; ++i)
if (type.getShape()[i] == -1)
++dynamicDimPos;
- return intrinsics::extractvalue(int64Ty, memref, pos(1 + dynamicDimPos));
+ return intrinsics::extractvalue(
+ int64Ty, memref, rewriter.getI64ArrayAttr({1, dynamicDimPos}));
};
// Helper function to obtain the data pointer of the given `memref`.
auto memrefPtr = [pos](MemRefType type, Value *memref) -> Value * {
- if (type.hasStaticShape())
- return memref;
-
auto elementTy = linalg::convertLinalgType(type.getElementType())
.cast<LLVM::LLVMType>()
.getPointerTo();
diff --git a/examples/toy/Ch5/mlir/LateLowering.cpp b/examples/toy/Ch5/mlir/LateLowering.cpp
index 95585f9..28dc717 100644
--- a/examples/toy/Ch5/mlir/LateLowering.cpp
+++ b/examples/toy/Ch5/mlir/LateLowering.cpp
@@ -149,6 +149,7 @@
// Create our loop nest now
using namespace edsc;
+ using extractvalue = intrinsics::ValueBuilder<LLVM::ExtractValueOp>;
using llvmCall = intrinsics::ValueBuilder<LLVM::CallOp>;
ScopedContext scope(rewriter, loc);
ValueHandle zero = intrinsics::constant_index(0);
@@ -157,26 +158,36 @@
IndexedValue iOp(operand);
IndexHandle i, j, M(vOp.ub(0));
+ auto *dialect = op->getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
+ auto i8PtrTy = LLVM::LLVMType::getInt8Ty(dialect).getPointerTo();
+
ValueHandle fmtEol(getConstantCharBuffer(rewriter, loc, "\n"));
if (vOp.rank() == 1) {
// clang-format off
LoopBuilder(&i, zero, M, 1)([&]{
llvmCall(retTy,
rewriter.getSymbolRefAttr(printfFunc),
- {fmtCst, iOp(i)});
+ {extractvalue(i8PtrTy, fmtCst, rewriter.getIndexArrayAttr(0)),
+ iOp(i)});
});
- llvmCall(retTy, rewriter.getSymbolRefAttr(printfFunc), {fmtEol});
+ llvmCall(retTy, rewriter.getSymbolRefAttr(printfFunc),
+ {extractvalue(i8PtrTy, fmtEol, rewriter.getIndexArrayAttr(0))});
// clang-format on
} else {
IndexHandle N(vOp.ub(1));
// clang-format off
LoopBuilder(&i, zero, M, 1)([&]{
LoopBuilder(&j, zero, N, 1)([&]{
- llvmCall(retTy,
- rewriter.getSymbolRefAttr(printfFunc),
- {fmtCst, iOp(i, j)});
+ llvmCall(
+ retTy,
+ rewriter.getSymbolRefAttr(printfFunc),
+ {extractvalue(i8PtrTy, fmtCst, rewriter.getIndexArrayAttr(0)),
+ iOp(i, j)});
});
- llvmCall(retTy, rewriter.getSymbolRefAttr(printfFunc), {fmtEol});
+ llvmCall(
+ retTy,
+ rewriter.getSymbolRefAttr(printfFunc),
+ {extractvalue(i8PtrTy, fmtEol, rewriter.getIndexArrayAttr(0))});
});
// clang-format on
}
diff --git a/g3doc/ConversionToLLVMDialect.md b/g3doc/ConversionToLLVMDialect.md
index 1e2ec95..6132615 100644
--- a/g3doc/ConversionToLLVMDialect.md
+++ b/g3doc/ConversionToLLVMDialect.md
@@ -52,36 +52,27 @@
Memref types in MLIR have both static and dynamic information associated with
them. The dynamic information comprises the buffer pointer as well as sizes of
-any dynamically sized dimensions. Memref types are converted into either LLVM IR
-pointer types if they are fully statically shaped; or to LLVM IR structure types
-if they contain dynamic sizes. In the latter case, the first element of the
-structure is a pointer to the converted (using these rules) memref element type,
-followed by as many elements as the memref has dynamic sizes. The type of each
-of these size arguments will be the LLVM type that results from converting the
-MLIR `index` type. Zero-dimensional memrefs are treated as pointers to the
-elemental type.
+any dynamically sized dimensions. Memref types are normalized and converted to a
+descriptor that is only dependent on the rank of the memref. The descriptor
+contains the pointer to the data buffer followed by an array containing as many
+64-bit integers as the rank of the memref. The array represents the size, in
+number of elements, of the memref along the given dimension. For constant memref
+dimensions, the corresponding size entry is a constant whose runtime value
+matches the static value. This normalization serves as an ABI for the memref
+type to interoperate with externally linked functions. In the particular case of
+rank `0` memrefs, the size array is omitted, resulting in a wrapped pointer.
Examples:
```mlir {.mlir}
-// All of the following are converted to just a pointer type because
-// of fully static sizes.
-memref<f32>
-memref<1 x f32>
-memref<10x42x42x43x123 x f32>
-// resulting type
-!llvm.type<"float*">
-
-// All of the following are converted to a three-element structure
-memref<?x? x f32>
-memref<42x?x10x35x1x? x f32>
-// resulting type assuming 64-bit pointers
-!llvm.type<"{float*, i64, i64}">
+memref<f32> -> !llvm.type<"{ float* }">
+memref<1 x f32> -> !llvm.type<"{ float*, [1 x i64] }">
+memref<? x f32> -> !llvm.type<"{ float*, [1 x i64] }">
+memref<10x42x42x43x123 x f32> -> !llvm.type<"{ float*, [5 x i64] }">
+memref<10x?x42x?x123 x f32> -> !llvm.type<"{ float*, [5 x i64] }">
// Memref types can have vectors as element types
-memref<1x? x vector<4xf32>>
-// which get converted as well
-!llvm.type<"{<4 x float>*, i64}">
+memref<1x? x vector<4xf32>> -> !llvm.type<"{ <4 x float>*, [1 x i64] }">
```
### Function Types
diff --git a/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp b/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp
index a67ff9d..968407a 100644
--- a/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp
+++ b/lib/Conversion/StandardToLLVM/ConvertStandardToLLVM.cpp
@@ -122,27 +122,38 @@
.getPointerTo();
}
-// Convert a MemRef to an LLVM type. If the memref is statically-shaped, then
-// we return a pointer to the converted element type. Otherwise we return an
-// LLVM structure type, where the first element of the structure type is a
-// pointer to the elemental type of the MemRef and the following N elements are
-// values of the Index type, one for each of N dynamic dimensions of the MemRef.
+// Convert a MemRef to an LLVM type. The result is a MemRef descriptor which
+// contains:
+// 1. the pointer to the data buffer, followed by
+// 2. an array containing as many 64-bit integers as the rank of the MemRef:
+// the array represents the size, in number of elements, of the memref along
+// the given dimension. For constant MemRef dimensions, the corresponding size
+// entry is a constant whose runtime value must match the static value.
+// TODO(ntv, zinenko): add assertions for the static cases.
+//
+// template <typename Elem, size_t Rank>
+// struct {
+// Elem *ptr;
+// int64_t sizes[Rank]; // omitted when rank == 0
+// };
+static unsigned kPtrPosInMemRefDescriptor = 0;
+static unsigned kSizePosInMemRefDescriptor = 1;
Type LLVMTypeConverter::convertMemRefType(MemRefType type) {
+ assert((type.getAffineMaps().empty() ||
+ (type.getAffineMaps().size() == 1 &&
+ type.getAffineMaps().back().isIdentity())) &&
+ "Non-identity layout maps must have been normalized away");
LLVM::LLVMType elementType = unwrap(convertType(type.getElementType()));
if (!elementType)
return {};
- auto ptrType = elementType.getPointerTo(type.getMemorySpace());
-
- // Extra value for the memory space.
- unsigned numDynamicSizes = type.getNumDynamicDims();
- // If memref is statically-shaped we return the underlying pointer type.
- if (numDynamicSizes == 0)
- return ptrType;
-
- SmallVector<LLVM::LLVMType, 8> types(numDynamicSizes + 1, getIndexType());
- types.front() = ptrType;
-
- return LLVM::LLVMType::getStructTy(llvmDialect, types);
+ auto ptrTy = elementType.getPointerTo(type.getMemorySpace());
+ auto indexTy = getIndexType();
+ auto rank = type.getRank();
+ if (rank > 0) {
+ auto arrayTy = LLVM::LLVMType::getArrayTy(indexTy, type.getRank());
+ return LLVM::LLVMType::getStructTy(ptrTy, arrayTy);
+ }
+ return LLVM::LLVMType::getStructTy(ptrTy);
}
// Convert an n-D vector type to an LLVM vector type via (n-1)-D array type when
@@ -600,10 +611,6 @@
allocated = rewriter.create<LLVM::BitcastOp>(op->getLoc(), elementPtrType,
ArrayRef<Value *>(allocated));
- // Deal with static memrefs
- if (numOperands == 0)
- return rewriter.replaceOp(op, allocated);
-
// Create the MemRef descriptor.
auto structType = lowering.convertType(type);
Value *memRefDescriptor = rewriter.create<LLVM::UndefOp>(
@@ -611,14 +618,15 @@
memRefDescriptor = rewriter.create<LLVM::InsertValueOp>(
op->getLoc(), structType, memRefDescriptor, allocated,
- rewriter.getIndexArrayAttr(0));
+ rewriter.getIndexArrayAttr(kPtrPosInMemRefDescriptor));
- // Store dynamically allocated sizes in the descriptor. Dynamic sizes are
- // passed in as operands.
- for (auto indexedSize : llvm::enumerate(operands)) {
+ // Store dynamically allocated sizes in the descriptor. Static and dynamic
+ // sizes are all passed in as operands.
+ for (auto indexedSize : llvm::enumerate(sizes)) {
+ int64_t index = indexedSize.index();
memRefDescriptor = rewriter.create<LLVM::InsertValueOp>(
op->getLoc(), structType, memRefDescriptor, indexedSize.value(),
- rewriter.getIndexArrayAttr(1 + indexedSize.index()));
+ rewriter.getI64ArrayAttr({kSizePosInMemRefDescriptor, index}));
}
// Return the final value of the descriptor.
@@ -679,60 +687,12 @@
ConversionPatternRewriter &rewriter) const override {
auto memRefCastOp = cast<MemRefCastOp>(op);
OperandAdaptor<MemRefCastOp> transformed(operands);
- auto targetType = memRefCastOp.getType();
- auto sourceType = memRefCastOp.getOperand()->getType().cast<MemRefType>();
-
- // Copy the data buffer pointer.
- auto elementTypePtr = getMemRefElementPtrType(targetType, lowering);
- Value *buffer =
- extractMemRefElementPtr(rewriter, op->getLoc(), transformed.source(),
- elementTypePtr, sourceType.hasStaticShape());
- // Account for static memrefs as target types
- if (targetType.hasStaticShape())
- return rewriter.replaceOp(op, buffer);
-
- // Create the new MemRef descriptor.
- auto structType = lowering.convertType(targetType);
- Value *newDescriptor = rewriter.create<LLVM::UndefOp>(
- op->getLoc(), structType, ArrayRef<Value *>{});
- // Otherwise target type is dynamic memref, so create a proper descriptor.
- newDescriptor = rewriter.create<LLVM::InsertValueOp>(
- op->getLoc(), structType, newDescriptor, buffer,
- rewriter.getIndexArrayAttr(0));
-
- // Fill in the dynamic sizes of the new descriptor. If the size was
- // dynamic, copy it from the old descriptor. If the size was static, insert
- // the constant. Note that the positions of dynamic sizes in the
- // descriptors start from 1 (the buffer pointer is at position zero).
- int64_t sourceDynamicDimIdx = 1;
- int64_t targetDynamicDimIdx = 1;
- for (int i = 0, e = sourceType.getRank(); i < e; ++i) {
- // Ignore new static sizes (they will be known from the type). If the
- // size was dynamic, update the index of dynamic types.
- if (targetType.getShape()[i] != -1) {
- if (sourceType.getShape()[i] == -1)
- ++sourceDynamicDimIdx;
- continue;
- }
-
- auto sourceSize = sourceType.getShape()[i];
- Value *size =
- sourceSize == -1
- ? rewriter.create<LLVM::ExtractValueOp>(
- op->getLoc(), getIndexType(),
- transformed.source(), // NB: dynamic memref
- rewriter.getIndexArrayAttr(sourceDynamicDimIdx++))
- : createIndexConstant(rewriter, op->getLoc(), sourceSize);
- newDescriptor = rewriter.create<LLVM::InsertValueOp>(
- op->getLoc(), structType, newDescriptor, size,
- rewriter.getIndexArrayAttr(targetDynamicDimIdx++));
- }
- assert(sourceDynamicDimIdx - 1 == sourceType.getNumDynamicDims() &&
- "source dynamic dimensions were not processed");
- assert(targetDynamicDimIdx - 1 == targetType.getNumDynamicDims() &&
- "target dynamic dimensions were not set up");
-
- rewriter.replaceOp(op, newDescriptor);
+ // memref_cast is defined for source and destination memref types with the
+ // same element type, same mappings, same address space and same rank.
+ // Therefore a simple bitcast suffices. If not it is undefined behavior.
+ auto targetStructType = lowering.convertType(memRefCastOp.getType());
+ rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(op, targetStructType,
+ transformed.source());
}
};
@@ -754,25 +714,16 @@
MemRefType type = dimOp.getOperand()->getType().cast<MemRefType>();
auto shape = type.getShape();
- uint64_t index = dimOp.getIndex();
+ int64_t index = dimOp.getIndex();
// Extract dynamic size from the memref descriptor and define static size
// as a constant.
- if (shape[index] == -1) {
- // Find the position of the dynamic dimension in the list of dynamic sizes
- // by counting the number of preceding dynamic dimensions. Start from 1
- // because the buffer pointer is at position zero.
- int64_t position = 1;
- for (uint64_t i = 0; i < index; ++i) {
- if (shape[i] == -1)
- ++position;
- }
+ if (ShapedType::isDynamic(shape[index]))
rewriter.replaceOpWithNewOp<LLVM::ExtractValueOp>(
op, getIndexType(), transformed.memrefOrTensor(),
- rewriter.getIndexArrayAttr(position));
- } else {
+ rewriter.getI64ArrayAttr({kSizePosInMemRefDescriptor, index}));
+ else
rewriter.replaceOp(
op, createIndexConstant(rewriter, op->getLoc(), shape[index]));
- }
}
};
@@ -829,61 +780,41 @@
// Dynamic sizes are extracted from the MemRef descriptor, where they start
// from the position 1 (the buffer is at position 0).
SmallVector<Value *, 4> sizes;
- unsigned dynamicSizeIdx = 1;
- for (int64_t s : shape) {
+ for (auto en : llvm::enumerate(shape)) {
+ int64_t s = en.value();
+ int64_t index = en.index();
if (s == -1) {
Value *size = rewriter.create<LLVM::ExtractValueOp>(
loc, this->getIndexType(), memRefDescriptor,
- rewriter.getIndexArrayAttr(dynamicSizeIdx++));
+ rewriter.getI64ArrayAttr({kSizePosInMemRefDescriptor, index}));
sizes.push_back(size);
} else {
sizes.push_back(this->createIndexConstant(rewriter, loc, s));
+ // TODO(ntv, zinenko): assert dynamic descriptor size is constant.
}
}
// The second and subsequent operands are access subscripts. Obtain the
// linearized address in the buffer.
- Value *subscript = linearizeSubscripts(rewriter, loc, indices, sizes);
+ Value *subscript = indices.empty()
+ ? nullptr
+ : linearizeSubscripts(rewriter, loc, indices, sizes);
Value *dataPtr = rewriter.create<LLVM::ExtractValueOp>(
- loc, elementTypePtr, memRefDescriptor, rewriter.getIndexArrayAttr(0));
- return rewriter.create<LLVM::GEPOp>(loc, elementTypePtr,
- ArrayRef<Value *>{dataPtr, subscript},
+ loc, elementTypePtr, memRefDescriptor,
+ rewriter.getIndexArrayAttr(kPtrPosInMemRefDescriptor));
+ SmallVector<Value *, 2> gepSubValues(1, dataPtr);
+ if (subscript)
+ gepSubValues.push_back(subscript);
+ return rewriter.create<LLVM::GEPOp>(loc, elementTypePtr, gepSubValues,
ArrayRef<NamedAttribute>{});
}
- // This is a getElementPtr variant, where the value is a direct raw pointer.
- // If a shape is empty, we are dealing with a zero-dimensional memref. Return
- // the pointer unmodified in this case. Otherwise, linearize subscripts to
- // obtain the offset with respect to the base pointer. Use this offset to
- // compute and return the element pointer.
- Value *getRawElementPtr(Location loc, Type elementTypePtr,
- ArrayRef<int64_t> shape, Value *rawDataPtr,
- ArrayRef<Value *> indices,
- ConversionPatternRewriter &rewriter) const {
- if (shape.empty())
- return rawDataPtr;
-
- SmallVector<Value *, 4> sizes;
- for (int64_t s : shape) {
- sizes.push_back(this->createIndexConstant(rewriter, loc, s));
- }
-
- Value *subscript = linearizeSubscripts(rewriter, loc, indices, sizes);
- return rewriter.create<LLVM::GEPOp>(
- loc, elementTypePtr, ArrayRef<Value *>{rawDataPtr, subscript},
- ArrayRef<NamedAttribute>{});
- }
-
Value *getDataPtr(Location loc, MemRefType type, Value *dataPtr,
ArrayRef<Value *> indices,
ConversionPatternRewriter &rewriter,
llvm::Module &module) const {
auto ptrType = getMemRefElementPtrType(type, this->lowering);
auto shape = type.getShape();
- if (type.hasStaticShape()) {
- // NB: If memref was statically-shaped, dataPtr is pointer to raw data.
- return getRawElementPtr(loc, ptrType, shape, dataPtr, indices, rewriter);
- }
return getElementPtr(loc, ptrType, shape, dataPtr, indices, rewriter);
}
};
diff --git a/test/Conversion/StandardToLLVM/convert-argattrs.mlir b/test/Conversion/StandardToLLVM/convert-argattrs.mlir
index 1617fd4..4c4b620 100644
--- a/test/Conversion/StandardToLLVM/convert-argattrs.mlir
+++ b/test/Conversion/StandardToLLVM/convert-argattrs.mlir
@@ -1,7 +1,7 @@
// RUN: mlir-opt -lower-to-llvm %s | FileCheck %s
-// CHECK-LABEL: func @check_attributes(%arg0: !llvm<"float*"> {dialect.a = true, dialect.b = 4 : i64}) {
+// CHECK-LABEL: func @check_attributes(%arg0: !llvm<"{ float*, [2 x i64] }"> {dialect.a = true, dialect.b = 4 : i64}) {
func @check_attributes(%static: memref<10x20xf32> {dialect.a = true, dialect.b = 4 : i64 }) {
return
}
diff --git a/test/Conversion/StandardToLLVM/convert-memref-ops.mlir b/test/Conversion/StandardToLLVM/convert-memref-ops.mlir
index 8cd1e98..496a1ec 100644
--- a/test/Conversion/StandardToLLVM/convert-memref-ops.mlir
+++ b/test/Conversion/StandardToLLVM/convert-memref-ops.mlir
@@ -1,18 +1,18 @@
// RUN: mlir-opt -lower-to-llvm %s | FileCheck %s
-// CHECK-LABEL: func @check_arguments(%arg0: !llvm<"float*">, %arg1: !llvm<"{ float*, i64, i64 }">, %arg2: !llvm<"{ float*, i64 }">)
+// CHECK-LABEL: func @check_arguments(%arg0: !llvm<"{ float*, [2 x i64] }">, %arg1: !llvm<"{ float*, [2 x i64] }">, %arg2: !llvm<"{ float*, [2 x i64] }">)
func @check_arguments(%static: memref<10x20xf32>, %dynamic : memref<?x?xf32>, %mixed : memref<10x?xf32>) {
return
}
-// CHECK-LABEL: func @check_static_return(%arg0: !llvm<"float*">) -> !llvm<"float*"> {
+// CHECK-LABEL: func @check_static_return(%arg0: !llvm<"{ float*, [2 x i64] }">) -> !llvm<"{ float*, [2 x i64] }"> {
func @check_static_return(%static : memref<32x18xf32>) -> memref<32x18xf32> {
-// CHECK-NEXT: llvm.return %arg0 : !llvm<"float*">
+// CHECK-NEXT: llvm.return %arg0 : !llvm<"{ float*, [2 x i64] }">
return %static : memref<32x18xf32>
}
-// CHECK-LABEL: func @zero_d_alloc() -> !llvm<"float*"> {
+// CHECK-LABEL: func @zero_d_alloc() -> !llvm<"{ float* }"> {
func @zero_d_alloc() -> memref<f32> {
// CHECK-NEXT: %0 = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK-NEXT: %1 = llvm.mlir.constant(4 : index) : !llvm.i64
@@ -23,15 +23,16 @@
return %0 : memref<f32>
}
-// CHECK-LABEL: func @zero_d_dealloc(%arg0: !llvm<"float*">) {
+// CHECK-LABEL: func @zero_d_dealloc(%arg0: !llvm<"{ float* }">) {
func @zero_d_dealloc(%arg0: memref<f32>) {
-// CHECK-NEXT: %0 = llvm.bitcast %arg0 : !llvm<"float*"> to !llvm<"i8*">
-// CHECK-NEXT: llvm.call @free(%0) : (!llvm<"i8*">) -> ()
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float* }">
+// CHECK-NEXT: %[[bc:.*]] = llvm.bitcast %[[ptr]] : !llvm<"float*"> to !llvm<"i8*">
+// CHECK-NEXT: llvm.call @free(%[[bc]]) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<f32>
return
}
-// CHECK-LABEL: func @mixed_alloc(%arg0: !llvm.i64, %arg1: !llvm.i64) -> !llvm<"{ float*, i64, i64 }"> {
+// CHECK-LABEL: func @mixed_alloc(%arg0: !llvm.i64, %arg1: !llvm.i64) -> !llvm<"{ float*, [3 x i64] }"> {
func @mixed_alloc(%arg0: index, %arg1: index) -> memref<?x42x?xf32> {
// CHECK-NEXT: %0 = llvm.mlir.constant(42 : index) : !llvm.i64
// CHECK-NEXT: %1 = llvm.mul %arg0, %0 : !llvm.i64
@@ -40,17 +41,18 @@
// CHECK-NEXT: %4 = llvm.mul %2, %3 : !llvm.i64
// CHECK-NEXT: %5 = llvm.call @malloc(%4) : (!llvm.i64) -> !llvm<"i8*">
// CHECK-NEXT: %6 = llvm.bitcast %5 : !llvm<"i8*"> to !llvm<"float*">
-// CHECK-NEXT: %7 = llvm.mlir.undef : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %8 = llvm.insertvalue %6, %7[0 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %9 = llvm.insertvalue %arg0, %8[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %10 = llvm.insertvalue %arg1, %9[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %7 = llvm.mlir.undef : !llvm<"{ float*, [3 x i64] }">
+// CHECK-NEXT: %8 = llvm.insertvalue %6, %7[0 : index] : !llvm<"{ float*, [3 x i64] }">
+// CHECK-NEXT: %9 = llvm.insertvalue %arg0, %8[1, 0] : !llvm<"{ float*, [3 x i64] }">
+// CHECK-NEXT: %10 = llvm.insertvalue %0, %9[1, 1] : !llvm<"{ float*, [3 x i64] }">
+// CHECK-NEXT: %11 = llvm.insertvalue %arg1, %10[1, 2] : !llvm<"{ float*, [3 x i64] }">
%0 = alloc(%arg0, %arg1) : memref<?x42x?xf32>
return %0 : memref<?x42x?xf32>
}
-// CHECK-LABEL: func @mixed_dealloc(%arg0: !llvm<"{ float*, i64, i64 }">) {
+// CHECK-LABEL: func @mixed_dealloc(%arg0: !llvm<"{ float*, [3 x i64] }">) {
func @mixed_dealloc(%arg0: memref<?x42x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [3 x i64] }">
// CHECK-NEXT: %1 = llvm.bitcast %0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%1) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x42x?xf32>
@@ -58,31 +60,31 @@
return
}
-// CHECK-LABEL: func @dynamic_alloc(%arg0: !llvm.i64, %arg1: !llvm.i64) -> !llvm<"{ float*, i64, i64 }"> {
+// CHECK-LABEL: func @dynamic_alloc(%arg0: !llvm.i64, %arg1: !llvm.i64) -> !llvm<"{ float*, [2 x i64] }"> {
func @dynamic_alloc(%arg0: index, %arg1: index) -> memref<?x?xf32> {
// CHECK-NEXT: %0 = llvm.mul %arg0, %arg1 : !llvm.i64
// CHECK-NEXT: %1 = llvm.mlir.constant(4 : index) : !llvm.i64
// CHECK-NEXT: %2 = llvm.mul %0, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.call @malloc(%2) : (!llvm.i64) -> !llvm<"i8*">
// CHECK-NEXT: %4 = llvm.bitcast %3 : !llvm<"i8*"> to !llvm<"float*">
-// CHECK-NEXT: %5 = llvm.mlir.undef : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %6 = llvm.insertvalue %4, %5[0 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %7 = llvm.insertvalue %arg0, %6[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %8 = llvm.insertvalue %arg1, %7[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %5 = llvm.mlir.undef : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %6 = llvm.insertvalue %4, %5[0 : index] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %7 = llvm.insertvalue %arg0, %6[1, 0] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %8 = llvm.insertvalue %arg1, %7[1, 1] : !llvm<"{ float*, [2 x i64] }">
%0 = alloc(%arg0, %arg1) : memref<?x?xf32>
return %0 : memref<?x?xf32>
}
-// CHECK-LABEL: func @dynamic_dealloc(%arg0: !llvm<"{ float*, i64, i64 }">) {
+// CHECK-LABEL: func @dynamic_dealloc(%arg0: !llvm<"{ float*, [2 x i64] }">) {
func @dynamic_dealloc(%arg0: memref<?x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %1 = llvm.bitcast %0 : !llvm<"float*"> to !llvm<"i8*">
// CHECK-NEXT: llvm.call @free(%1) : (!llvm<"i8*">) -> ()
dealloc %arg0 : memref<?x?xf32>
return
}
-// CHECK-LABEL: func @static_alloc() -> !llvm<"float*"> {
+// CHECK-LABEL: func @static_alloc() -> !llvm<"{ float*, [2 x i64] }"> {
func @static_alloc() -> memref<32x18xf32> {
// CHECK-NEXT: %0 = llvm.mlir.constant(32 : index) : !llvm.i64
// CHECK-NEXT: %1 = llvm.mlir.constant(18 : index) : !llvm.i64
@@ -95,17 +97,20 @@
return %0 : memref<32x18xf32>
}
-// CHECK-LABEL: func @static_dealloc(%arg0: !llvm<"float*">) {
+// CHECK-LABEL: func @static_dealloc(%arg0: !llvm<"{ float*, [2 x i64] }">) {
func @static_dealloc(%static: memref<10x8xf32>) {
-// CHECK-NEXT: %0 = llvm.bitcast %arg0 : !llvm<"float*"> to !llvm<"i8*">
-// CHECK-NEXT: llvm.call @free(%0) : (!llvm<"i8*">) -> ()
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %[[bc:.*]] = llvm.bitcast %[[ptr]] : !llvm<"float*"> to !llvm<"i8*">
+// CHECK-NEXT: llvm.call @free(%[[bc]]) : (!llvm<"i8*">) -> ()
dealloc %static : memref<10x8xf32>
return
}
-// CHECK-LABEL: func @zero_d_load(%arg0: !llvm<"float*">) -> !llvm.float {
+// CHECK-LABEL: func @zero_d_load(%arg0: !llvm<"{ float* }">) -> !llvm.float {
func @zero_d_load(%arg0: memref<f32>) -> f32 {
-// CHECK-NEXT: %0 = llvm.load %arg0 : !llvm<"float*">
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float* }">
+// CHECK-NEXT: %[[addr:.*]] = llvm.getelementptr %[[ptr]][] : (!llvm<"float*">) -> !llvm<"float*">
+// CHECK-NEXT: %2 = llvm.load %[[addr]] : !llvm<"float*">
%0 = load %arg0[] : memref<f32>
return %0 : f32
}
@@ -116,8 +121,9 @@
// CHECK-NEXT: %1 = llvm.mlir.constant(42 : index) : !llvm.i64
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.getelementptr %arg0[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
-// CHECK-NEXT: %5 = llvm.load %4 : !llvm<"float*">
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %[[addr:.*]] = llvm.getelementptr %[[ptr]][%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
+// CHECK-NEXT: llvm.load %[[addr]] : !llvm<"float*">
%0 = load %static[%i, %j] : memref<10x42xf32>
return
}
@@ -125,10 +131,10 @@
// CHECK-LABEL: func @mixed_load
func @mixed_load(%mixed : memref<42x?xf32>, %i : index, %j : index) {
// CHECK-NEXT: %0 = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
// CHECK-NEXT: %6 = llvm.load %5 : !llvm<"float*">
%0 = load %mixed[%i, %j] : memref<42x?xf32>
@@ -137,20 +143,22 @@
// CHECK-LABEL: func @dynamic_load
func @dynamic_load(%dynamic : memref<?x?xf32>, %i : index, %j : index) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %1 = llvm.extractvalue %arg0[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1, 0] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
// CHECK-NEXT: %6 = llvm.load %5 : !llvm<"float*">
%0 = load %dynamic[%i, %j] : memref<?x?xf32>
return
}
-// CHECK-LABEL: func @zero_d_store(%arg0: !llvm<"float*">, %arg1: !llvm.float) {
+// CHECK-LABEL: func @zero_d_store(%arg0: !llvm<"{ float* }">, %arg1: !llvm.float) {
func @zero_d_store(%arg0: memref<f32>, %arg1: f32) {
-// CHECK-NEXT: llvm.store %arg1, %arg0 : !llvm<"float*">
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float* }">
+// CHECK-NEXT: %[[addr:.*]] = llvm.getelementptr %[[ptr]][] : (!llvm<"float*">) -> !llvm<"float*">
+// CHECK-NEXT: llvm.store %arg1, %[[addr]] : !llvm<"float*">
store %arg1, %arg0[] : memref<f32>
return
}
@@ -161,19 +169,20 @@
// CHECK-NEXT: %1 = llvm.mlir.constant(42 : index) : !llvm.i64
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.getelementptr %arg0[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
-// CHECK-NEXT: llvm.store %arg3, %4 : !llvm<"float*">
+// CHECK-NEXT: %[[ptr:.*]] = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %[[addr:.*]] = llvm.getelementptr %[[ptr]][%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
+// CHECK-NEXT: llvm.store %arg3, %[[addr]] : !llvm<"float*">
store %val, %static[%i, %j] : memref<10x42xf32>
return
}
// CHECK-LABEL: func @dynamic_store
func @dynamic_store(%dynamic : memref<?x?xf32>, %i : index, %j : index, %val : f32) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %1 = llvm.extractvalue %arg0[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %0 = llvm.extractvalue %arg0[1, 0] : !llvm<"{ float*, [2 x i64] }">
+// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
// CHECK-NEXT: llvm.store %arg3, %5 : !llvm<"float*">
store %val, %dynamic[%i, %j] : memref<?x?xf32>
@@ -183,10 +192,10 @@
// CHECK-LABEL: func @mixed_store
func @mixed_store(%mixed : memref<42x?xf32>, %i : index, %j : index, %val : f32) {
// CHECK-NEXT: %0 = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %2 = llvm.mul %arg1, %1 : !llvm.i64
// CHECK-NEXT: %3 = llvm.add %2, %arg2 : !llvm.i64
-// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: %4 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, [2 x i64] }">
// CHECK-NEXT: %5 = llvm.getelementptr %4[%3] : (!llvm<"float*">, !llvm.i64) -> !llvm<"float*">
// CHECK-NEXT: llvm.store %arg3, %5 : !llvm<"float*">
store %val, %mixed[%i, %j] : memref<42x?xf32>
@@ -195,91 +204,69 @@
// CHECK-LABEL: func @memref_cast_static_to_dynamic
func @memref_cast_static_to_dynamic(%static : memref<10x42xf32>) {
-// CHECK-NEXT: %0 = llvm.mlir.undef : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %1 = llvm.insertvalue %arg0, %0[0 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %2 = llvm.mlir.constant(10 : index) : !llvm.i64
-// CHECK-NEXT: %3 = llvm.insertvalue %2, %1[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %4 = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: %5 = llvm.insertvalue %4, %3[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %static : memref<10x42xf32> to memref<?x?xf32>
return
}
// CHECK-LABEL: func @memref_cast_static_to_mixed
func @memref_cast_static_to_mixed(%static : memref<10x42xf32>) {
-// CHECK-NEXT: %0 = llvm.mlir.undef : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %1 = llvm.insertvalue %arg0, %0[0 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %2 = llvm.mlir.constant(10 : index) : !llvm.i64
-// CHECK-NEXT: %3 = llvm.insertvalue %2, %1[1 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %static : memref<10x42xf32> to memref<?x42xf32>
return
}
// CHECK-LABEL: func @memref_cast_dynamic_to_static
func @memref_cast_dynamic_to_static(%dynamic : memref<?x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %dynamic : memref<?x?xf32> to memref<10x12xf32>
return
}
// CHECK-LABEL: func @memref_cast_dynamic_to_mixed
func @memref_cast_dynamic_to_mixed(%dynamic : memref<?x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %1 = llvm.mlir.undef : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %3 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %dynamic : memref<?x?xf32> to memref<?x12xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_dynamic
func @memref_cast_mixed_to_dynamic(%mixed : memref<42x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %1 = llvm.mlir.undef : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %3 = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1 : index] : !llvm<"{ float*, i64, i64 }">
-// CHECK-NEXT: %5 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %6 = llvm.insertvalue %5, %4[2 : index] : !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<?x?xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_static
func @memref_cast_mixed_to_static(%mixed : memref<42x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<42x1xf32>
return
}
// CHECK-LABEL: func @memref_cast_mixed_to_mixed
func @memref_cast_mixed_to_mixed(%mixed : memref<42x?xf32>) {
-// CHECK-NEXT: %0 = llvm.extractvalue %arg0[0 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %1 = llvm.mlir.undef : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %2 = llvm.insertvalue %0, %1[0 : index] : !llvm<"{ float*, i64 }">
-// CHECK-NEXT: %3 = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: %4 = llvm.insertvalue %3, %2[1 : index] : !llvm<"{ float*, i64 }">
+// CHECK-NEXT: llvm.bitcast %arg0 : !llvm<"{ float*, [2 x i64] }"> to !llvm<"{ float*, [2 x i64] }">
%0 = memref_cast %mixed : memref<42x?xf32> to memref<?x1xf32>
return
}
-// CHECK-LABEL: func @mixed_memref_dim(%arg0: !llvm<"{ float*, i64, i64, i64 }">)
+// CHECK-LABEL: func @mixed_memref_dim(%arg0: !llvm<"{ float*, [5 x i64] }">)
func @mixed_memref_dim(%mixed : memref<42x?x?x13x?xf32>) {
// CHECK-NEXT: %0 = llvm.mlir.constant(42 : index) : !llvm.i64
%0 = dim %mixed, 0 : memref<42x?x?x13x?xf32>
-// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1 : index] : !llvm<"{ float*, i64, i64, i64 }">
+// CHECK-NEXT: %1 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [5 x i64] }">
%1 = dim %mixed, 1 : memref<42x?x?x13x?xf32>
-// CHECK-NEXT: %2 = llvm.extractvalue %arg0[2 : index] : !llvm<"{ float*, i64, i64, i64 }">
+// CHECK-NEXT: %2 = llvm.extractvalue %arg0[1, 2] : !llvm<"{ float*, [5 x i64] }">
%2 = dim %mixed, 2 : memref<42x?x?x13x?xf32>
// CHECK-NEXT: %3 = llvm.mlir.constant(13 : index) : !llvm.i64
%3 = dim %mixed, 3 : memref<42x?x?x13x?xf32>
-// CHECK-NEXT: %4 = llvm.extractvalue %arg0[3 : index] : !llvm<"{ float*, i64, i64, i64 }">
+// CHECK-NEXT: %4 = llvm.extractvalue %arg0[1, 4] : !llvm<"{ float*, [5 x i64] }">
%4 = dim %mixed, 4 : memref<42x?x?x13x?xf32>
return
}
-// CHECK-LABEL: func @static_memref_dim(%arg0: !llvm<"float*">)
+// CHECK-LABEL: func @static_memref_dim(%arg0: !llvm<"{ float*, [5 x i64] }">)
func @static_memref_dim(%static : memref<42x32x15x13x27xf32>) {
// CHECK-NEXT: %0 = llvm.mlir.constant(42 : index) : !llvm.i64
%0 = dim %static, 0 : memref<42x32x15x13x27xf32>
diff --git a/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir b/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir
index b81f7fb..97054f6 100644
--- a/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir
+++ b/test/Conversion/StandardToLLVM/convert-to-llvmir.mlir
@@ -317,23 +317,23 @@
func @get_i64() -> (i64)
// CHECK-LABEL: func @get_f32() -> !llvm.float
func @get_f32() -> (f32)
-// CHECK-LABEL: func @get_memref() -> !llvm<"{ float*, i64, i64 }">
+// CHECK-LABEL: func @get_memref() -> !llvm<"{ float*, [4 x i64] }">
func @get_memref() -> (memref<42x?x10x?xf32>)
-// CHECK-LABEL: func @multireturn() -> !llvm<"{ i64, float, { float*, i64, i64 } }"> {
+// CHECK-LABEL: func @multireturn() -> !llvm<"{ i64, float, { float*, [4 x i64] } }"> {
func @multireturn() -> (i64, f32, memref<42x?x10x?xf32>) {
^bb0:
// CHECK-NEXT: {{.*}} = llvm.call @get_i64() : () -> !llvm.i64
// CHECK-NEXT: {{.*}} = llvm.call @get_f32() : () -> !llvm.float
-// CHECK-NEXT: {{.*}} = llvm.call @get_memref() : () -> !llvm<"{ float*, i64, i64 }">
+// CHECK-NEXT: {{.*}} = llvm.call @get_memref() : () -> !llvm<"{ float*, [4 x i64] }">
%0 = call @get_i64() : () -> (i64)
%1 = call @get_f32() : () -> (f32)
%2 = call @get_memref() : () -> (memref<42x?x10x?xf32>)
-// CHECK-NEXT: {{.*}} = llvm.mlir.undef : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[0 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[1 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[2 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: llvm.return {{.*}} : !llvm<"{ i64, float, { float*, i64, i64 } }">
+// CHECK-NEXT: {{.*}} = llvm.mlir.undef : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[0 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[1 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.insertvalue {{.*}}, {{.*}}[2 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: llvm.return {{.*}} : !llvm<"{ i64, float, { float*, [4 x i64] } }">
return %0, %1, %2 : i64, f32, memref<42x?x10x?xf32>
}
@@ -341,10 +341,10 @@
// CHECK-LABEL: func @multireturn_caller() {
func @multireturn_caller() {
^bb0:
-// CHECK-NEXT: {{.*}} = llvm.call @multireturn() : () -> !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[0 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[1 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
-// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[2 : index] : !llvm<"{ i64, float, { float*, i64, i64 } }">
+// CHECK-NEXT: {{.*}} = llvm.call @multireturn() : () -> !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[0 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[1 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
+// CHECK-NEXT: {{.*}} = llvm.extractvalue {{.*}}[2 : index] : !llvm<"{ i64, float, { float*, [4 x i64] } }">
%0:3 = call @multireturn() : () -> (i64, f32, memref<42x?x10x?xf32>)
%1 = constant 42 : i64
// CHECK: {{.*}} = llvm.add {{.*}}, {{.*}} : !llvm.i64
diff --git a/test/Conversion/StandardToLLVM/standard-to-llvm.mlir b/test/Conversion/StandardToLLVM/standard-to-llvm.mlir
index 9afb087..3f62fd4 100644
--- a/test/Conversion/StandardToLLVM/standard-to-llvm.mlir
+++ b/test/Conversion/StandardToLLVM/standard-to-llvm.mlir
@@ -1,6 +1,7 @@
// RUN: mlir-opt %s -lower-to-llvm | FileCheck %s
-// CHECK-LABEL: func @address_space(%{{.*}}: !llvm<"float addrspace(7)*">)
+// CHECK-LABEL: func @address_space(
+// CHECK: %{{.*}}: !llvm<"{ float addrspace(7)*, [1 x i64] }">)
func @address_space(%arg0 : memref<32xf32, (d0) -> (d0), 7>) {
%0 = alloc() : memref<32xf32, (d0) -> (d0), 5>
%1 = constant 7 : index
diff --git a/test/Examples/Linalg/Linalg1.mlir b/test/Examples/Linalg/Linalg1.mlir
index a5a3bac..03e16db 100644
--- a/test/Examples/Linalg/Linalg1.mlir
+++ b/test/Examples/Linalg/Linalg1.mlir
@@ -64,9 +64,9 @@
}
// LLVM-LABEL: @viewRangeConversion
// LLVM-NEXT: %0 = llvm.mlir.undef : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
-// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
+// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, [2 x i64] }">
// LLVM-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
-// LLVM-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }">
+// LLVM-NEXT: %3 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// LLVM-NEXT: %4 = llvm.mlir.constant(1 : index) : !llvm.i64
// LLVM-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64
// LLVM-NEXT: %6 = llvm.mlir.constant(0 : index) : !llvm.i64
@@ -98,9 +98,9 @@
}
// LLVM-LABEL: @viewNonRangeConversion
// LLVM-NEXT: %0 = llvm.mlir.undef : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
-// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, i64, i64 }">
+// LLVM-NEXT: %1 = llvm.extractvalue %arg0[0] : !llvm<"{ float*, [2 x i64] }">
// LLVM-NEXT: %2 = llvm.insertvalue %1, %0[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
-// LLVM-NEXT: %3 = llvm.extractvalue %arg0[2] : !llvm<"{ float*, i64, i64 }">
+// LLVM-NEXT: %3 = llvm.extractvalue %arg0[1, 1] : !llvm<"{ float*, [2 x i64] }">
// LLVM-NEXT: %4 = llvm.mlir.constant(1 : index) : !llvm.i64
// LLVM-NEXT: %5 = llvm.mul %4, %3 : !llvm.i64
// LLVM-NEXT: %6 = llvm.mlir.constant(0 : index) : !llvm.i64