std.alloc only supports memrefs with identity layout, which means we can simplify the lowering to LLVM and compute strides only from (static and dynamic) sizes.
Reviewed By: ftynse
Differential Revision: https://reviews.llvm.org/D91549
/// Returns the type of a pointer to an element of the memref.
Type getElementPtrType(MemRefType type) const;
- /// Determines sizes to be used in the memref descriptor.
+ /// Computes sizes, strides and buffer size in bytes of `memRefType` with
+ /// identity layout. Emits constant ops for the static sizes of `memRefType`,
+ /// and uses `dynamicSizes` for the others. Emits instructions to compute
+ /// strides and buffer size from these sizes.
+ ///
+ /// For example, memref<4x?xf32> emits:
+ /// `sizes[0]` = llvm.mlir.constant(4 : index) : !llvm.i64
+ /// `sizes[1]` = `dynamicSizes[0]`
+ /// `strides[1]` = llvm.mlir.constant(1 : index) : !llvm.i64
+ /// `strides[0]` = `sizes[0]`
+ /// %size = llvm.mul `sizes[0]`, `sizes[1]` : !llvm.i64
+ /// %nullptr = llvm.mlir.null : !llvm.ptr<float>
+ /// %gep = llvm.getelementptr %nullptr[%size]
+ /// : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+ /// `sizeBytes` = llvm.ptrtoint %gep : !llvm.ptr<float> to !llvm.i64
void getMemRefDescriptorSizes(Location loc, MemRefType memRefType,
- ArrayRef<Value> dynSizes,
+ ArrayRef<Value> dynamicSizes,
ConversionPatternRewriter &rewriter,
- SmallVectorImpl<Value> &sizes) const;
+ SmallVectorImpl<Value> &sizes,
+ SmallVectorImpl<Value> &strides,
+ Value &sizeBytes) const;
/// Computes the size of type in bytes.
Value getSizeInBytes(Location loc, Type type,
Value getNumElements(Location loc, ArrayRef<Value> shape,
ConversionPatternRewriter &rewriter) const;
- /// Computes total size in bytes of to store the given shape.
- Value getCumulativeSizeInBytes(Location loc, Type elementType,
- ArrayRef<Value> shape,
- ConversionPatternRewriter &rewriter) const;
-
- /// Creates and populates the memref descriptor struct given all its fields.
- /// 'strides' can be either dynamic (kDynamicStrideOrOffset) or static, but
- /// not a mix of the two.
+ /// Creates and populates a canonical memref descriptor struct.
MemRefDescriptor
createMemRefDescriptor(Location loc, MemRefType memRefType,
- Value allocatedPtr, Value alignedPtr, uint64_t offset,
- ArrayRef<int64_t> strides, ArrayRef<Value> sizes,
+ Value allocatedPtr, Value alignedPtr,
+ ArrayRef<Value> sizes, ArrayRef<Value> strides,
ConversionPatternRewriter &rewriter) const;
protected:
// Calculate the size of the memref and get the pointer to the allocated
// buffer.
SmallVector<Value, 4> sizes;
+ SmallVector<Value, 4> strides;
+ Value sizeBytes;
getMemRefDescriptorSizes(loc, memRefType, operand.value(), rewriter,
- sizes);
- Value size = getCumulativeSizeInBytes(loc, memRefType.getElementType(),
- sizes, rewriter);
+ sizes, strides, sizeBytes);
MemRefDescriptor descriptor(operand.value());
Value src = descriptor.allocatedPtr(rewriter, loc);
// src, dst and size so that we can copy data back after emulating the
// kernel call.
Value dst = rewriter.create<LLVM::AddressOfOp>(loc, dstGlobal);
- copy(loc, dst, src, size, rewriter);
+ copy(loc, dst, src, sizeBytes, rewriter);
CopyInfo info;
info.dst = dst;
info.src = src;
- info.size = size;
+ info.size = sizeBytes;
copyInfo.push_back(info);
}
// Create a call to the kernel and copy the data back.
}
void ConvertToLLVMPattern::getMemRefDescriptorSizes(
- Location loc, MemRefType memRefType, ArrayRef<Value> dynSizes,
- ConversionPatternRewriter &rewriter, SmallVectorImpl<Value> &sizes) const {
+ Location loc, MemRefType memRefType, ArrayRef<Value> dynamicSizes,
+ ConversionPatternRewriter &rewriter, SmallVectorImpl<Value> &sizes,
+ SmallVectorImpl<Value> &strides, Value &sizeBytes) const {
+ assert(isSupportedMemRefType(memRefType) &&
+ "layout maps must have been normalized away");
+
sizes.reserve(memRefType.getRank());
- unsigned i = 0;
- for (int64_t s : memRefType.getShape())
- sizes.push_back(s == ShapedType::kDynamicSize
- ? dynSizes[i++]
- : createIndexConstant(rewriter, loc, s));
+ unsigned dynamicIndex = 0;
+ for (int64_t size : memRefType.getShape()) {
+ sizes.push_back(size == ShapedType::kDynamicSize
+ ? dynamicSizes[dynamicIndex++]
+ : createIndexConstant(rewriter, loc, size));
+ }
+
+ // Strides: iterate sizes in reverse order and multiply.
+ int64_t stride = 1;
+ Value runningStride = createIndexConstant(rewriter, loc, 1);
+ strides.resize(memRefType.getRank());
+ for (auto i = memRefType.getRank(); i-- > 0;) {
+ strides[i] = runningStride;
+
+ int64_t size = memRefType.getShape()[i];
+ if (size == 0)
+ continue;
+ bool useSizeAsStride = stride == 1;
+ if (size == ShapedType::kDynamicSize)
+ stride = ShapedType::kDynamicSize;
+ if (stride != ShapedType::kDynamicSize)
+ stride *= size;
+
+ if (useSizeAsStride)
+ runningStride = sizes[i];
+ else if (stride == ShapedType::kDynamicSize)
+ runningStride =
+ rewriter.create<LLVM::MulOp>(loc, runningStride, sizes[i]);
+ else
+ runningStride = createIndexConstant(rewriter, loc, stride);
+ }
+
+ // Buffer size in bytes.
+ Type elementPtrType = getElementPtrType(memRefType);
+ Value nullPtr = rewriter.create<LLVM::NullOp>(loc, elementPtrType);
+ Value gepPtr = rewriter.create<LLVM::GEPOp>(
+ loc, elementPtrType, ArrayRef<Value>{nullPtr, runningStride});
+ sizeBytes = rewriter.create<LLVM::PtrToIntOp>(loc, getIndexType(), gepPtr);
}
Value ConvertToLLVMPattern::getSizeInBytes(
return numElements;
}
-Value ConvertToLLVMPattern::getCumulativeSizeInBytes(
- Location loc, Type elementType, ArrayRef<Value> shape,
- ConversionPatternRewriter &rewriter) const {
- Value numElements = this->getNumElements(loc, shape, rewriter);
- Value elementSize = this->getSizeInBytes(loc, elementType, rewriter);
- return rewriter.create<LLVM::MulOp>(loc, numElements, elementSize);
-}
-
/// Creates and populates the memref descriptor struct given all its fields.
MemRefDescriptor ConvertToLLVMPattern::createMemRefDescriptor(
Location loc, MemRefType memRefType, Value allocatedPtr, Value alignedPtr,
- uint64_t offset, ArrayRef<int64_t> strides, ArrayRef<Value> sizes,
+ ArrayRef<Value> sizes, ArrayRef<Value> strides,
ConversionPatternRewriter &rewriter) const {
auto structType = typeConverter.convertType(memRefType);
auto memRefDescriptor = MemRefDescriptor::undef(rewriter, loc, structType);
// Field 3: Offset in aligned pointer.
memRefDescriptor.setOffset(rewriter, loc,
- createIndexConstant(rewriter, loc, offset));
-
- if (memRefType.getRank() == 0)
- // No size/stride descriptor in memref, return the descriptor value.
- return memRefDescriptor;
-
- // Fields 4 and 5: sizes and strides of the strided MemRef.
- // Store all sizes in the descriptor. Only dynamic sizes are passed in as
- // operands to AllocOp.
- Value runningStride = nullptr;
- // Iterate strides in reverse order, compute runningStride and strideValues.
- auto nStrides = strides.size();
- SmallVector<Value, 4> strideValues(nStrides, nullptr);
- for (unsigned i = 0; i < nStrides; ++i) {
- int64_t index = nStrides - 1 - i;
- if (strides[index] == MemRefType::getDynamicStrideOrOffset())
- // Identity layout map is enforced in the match function, so we compute:
- // `runningStride *= sizes[index + 1]`
- runningStride = runningStride ? rewriter.create<LLVM::MulOp>(
- loc, runningStride, sizes[index + 1])
- : createIndexConstant(rewriter, loc, 1);
- else
- runningStride = createIndexConstant(rewriter, loc, strides[index]);
- strideValues[index] = runningStride;
- }
- // Fill size and stride descriptors in memref.
- for (auto indexedSize : llvm::enumerate(sizes)) {
- int64_t index = indexedSize.index();
- memRefDescriptor.setSize(rewriter, loc, index, indexedSize.value());
- memRefDescriptor.setStride(rewriter, loc, index, strideValues[index]);
- }
+ createIndexConstant(rewriter, loc, 0));
+
+ // Fields 4: Sizes.
+ for (auto en : llvm::enumerate(sizes))
+ memRefDescriptor.setSize(rewriter, loc, en.index(), en.value());
+
+ // Field 5: Strides.
+ for (auto en : llvm::enumerate(strides))
+ memRefDescriptor.setStride(rewriter, loc, en.index(), en.value());
+
return memRefDescriptor;
}
return rewriter.create<LLVM::BitcastOp>(loc, ptrType, allocatedPtr);
}
- /// Returns if buffer allocation needs buffer size to be computed. This size
- /// feeds into the `bufferSize` argument of `allocateBuffer`.
- virtual bool needsBufferSize() const { return true; }
-
/// Allocates the underlying buffer. Returns the allocated pointer and the
/// aligned pointer.
virtual std::tuple<Value, Value>
allocateBuffer(ConversionPatternRewriter &rewriter, Location loc,
- Value bufferSize, Operation *op) const = 0;
+ Value sizeBytes, Operation *op) const = 0;
private:
static MemRefType getMemRefResultType(Operation *op) {
// values and dynamic sizes are passed to 'alloc' as operands. In case of
// zero-dimensional memref, assume a scalar (size 1).
SmallVector<Value, 4> sizes;
- this->getMemRefDescriptorSizes(loc, memRefType, operands, rewriter, sizes);
-
- Value bufferSize;
- if (needsBufferSize())
- bufferSize = this->getCumulativeSizeInBytes(
- loc, memRefType.getElementType(), sizes, rewriter);
+ SmallVector<Value, 4> strides;
+ Value sizeBytes;
+ this->getMemRefDescriptorSizes(loc, memRefType, operands, rewriter, sizes,
+ strides, sizeBytes);
// Allocate the underlying buffer.
Value allocatedPtr;
Value alignedPtr;
std::tie(allocatedPtr, alignedPtr) =
- this->allocateBuffer(rewriter, loc, bufferSize, op);
-
- int64_t offset;
- SmallVector<int64_t, 4> strides;
- auto successStrides = getStridesAndOffset(memRefType, strides, offset);
- (void)successStrides;
- assert(succeeded(successStrides) && "unexpected non-strided memref");
- assert(offset != MemRefType::getDynamicStrideOrOffset() &&
- "unexpected dynamic offset");
-
- // 0-D memref corner case: they have size 1.
- assert(
- ((memRefType.getRank() == 0 && strides.empty() && sizes.size() == 1) ||
- (strides.size() == sizes.size())) &&
- "unexpected number of strides");
+ this->allocateBuffer(rewriter, loc, sizeBytes, op);
// Create the MemRef descriptor.
- auto memRefDescriptor =
- this->createMemRefDescriptor(loc, memRefType, allocatedPtr, alignedPtr,
- offset, strides, sizes, rewriter);
+ auto memRefDescriptor = this->createMemRefDescriptor(
+ loc, memRefType, allocatedPtr, alignedPtr, sizes, strides, rewriter);
// Return the final value of the descriptor.
rewriter.replaceOp(op, {memRefDescriptor});
: AllocLikeOpLowering(AllocOp::getOperationName(), converter) {}
std::tuple<Value, Value> allocateBuffer(ConversionPatternRewriter &rewriter,
- Location loc, Value bufferSize,
+ Location loc, Value sizeBytes,
Operation *op) const override {
// Heap allocations.
AllocOp allocOp = cast<AllocOp>(op);
if (alignment) {
// Adjust the allocation size to consider alignment.
- bufferSize = rewriter.create<LLVM::AddOp>(loc, bufferSize, alignment);
+ sizeBytes = rewriter.create<LLVM::AddOp>(loc, sizeBytes, alignment);
}
// Allocate the underlying buffer and store a pointer to it in the MemRef
// descriptor.
Type elementPtrType = this->getElementPtrType(memRefType);
Value allocatedPtr =
- createAllocCall(loc, "malloc", elementPtrType, {bufferSize},
+ createAllocCall(loc, "malloc", elementPtrType, {sizeBytes},
allocOp.getParentOfType<ModuleOp>(), rewriter);
Value alignedPtr = allocatedPtr;
}
std::tuple<Value, Value> allocateBuffer(ConversionPatternRewriter &rewriter,
- Location loc, Value bufferSize,
+ Location loc, Value sizeBytes,
Operation *op) const override {
// Heap allocations.
AllocOp allocOp = cast<AllocOp>(op);
// aligned_alloc requires size to be a multiple of alignment; we will pad
// the size to the next multiple if necessary.
if (!isMemRefSizeMultipleOf(memRefType, alignment))
- bufferSize = createAligned(rewriter, loc, bufferSize, allocAlignment);
+ sizeBytes = createAligned(rewriter, loc, sizeBytes, allocAlignment);
Type elementPtrType = this->getElementPtrType(memRefType);
Value allocatedPtr = createAllocCall(
- loc, "aligned_alloc", elementPtrType, {allocAlignment, bufferSize},
+ loc, "aligned_alloc", elementPtrType, {allocAlignment, sizeBytes},
allocOp.getParentOfType<ModuleOp>(), rewriter);
return std::make_tuple(allocatedPtr, allocatedPtr);
/// is set to null for stack allocations. `accessAlignment` is set if
/// alignment is needed post allocation (for eg. in conjunction with malloc).
std::tuple<Value, Value> allocateBuffer(ConversionPatternRewriter &rewriter,
- Location loc, Value bufferSize,
+ Location loc, Value sizeBytes,
Operation *op) const override {
// With alloca, one gets a pointer to the element type right away.
auto elementPtrType = this->getElementPtrType(allocaOp.getType());
auto allocatedElementPtr = rewriter.create<LLVM::AllocaOp>(
- loc, elementPtrType, bufferSize,
+ loc, elementPtrType, sizeBytes,
allocaOp.alignment() ? *allocaOp.alignment() : 0);
return std::make_tuple(allocatedElementPtr, allocatedElementPtr);
GetGlobalMemrefOpLowering(LLVMTypeConverter &converter)
: AllocLikeOpLowering(GetGlobalMemrefOp::getOperationName(), converter) {}
- /// Allocation for GetGlobalMemrefOp just returns the GV pointer, so no need
- /// to compute buffer size.
- bool needsBufferSize() const override { return false; }
-
/// Buffer "allocation" for get_global_memref op is getting the address of
/// the global variable referenced.
std::tuple<Value, Value> allocateBuffer(ConversionPatternRewriter &rewriter,
- Location loc, Value bufferSize,
+ Location loc, Value sizeBytes,
Operation *op) const override {
auto getGlobalOp = cast<GetGlobalMemrefOp>(op);
MemRefType type = getGlobalOp.result().getType().cast<MemRefType>();
// CHECK: %[[M:.*]]: !llvm.i64, %[[N:.*]]: !llvm.i64) -> !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)> {
func @mixed_alloc(%arg0: index, %arg1: index) -> memref<?x42x?xf32> {
// CHECK: %[[c42:.*]] = llvm.mlir.constant(42 : index) : !llvm.i64
-// CHECK-NEXT: llvm.mul %[[M]], %[[c42]] : !llvm.i64
-// CHECK-NEXT: %[[sz:.*]] = llvm.mul %{{.*}}, %[[N]] : !llvm.i64
-// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.mul %[[sz]], %[[sizeof]] : !llvm.i64
+// CHECK-NEXT: %[[st0:.*]] = llvm.mul %[[N]], %[[c42]] : !llvm.i64
+// CHECK-NEXT: %[[sz:.*]] = llvm.mul %[[st0]], %[[M]] : !llvm.i64
+// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// CHECK-NEXT: llvm.call @malloc(%[[sz_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// CHECK-NEXT: llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// CHECK-NEXT: llvm.mlir.undef : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
// CHECK-NEXT: %[[off:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[off]], %{{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
-// CHECK-NEXT: %[[st2:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[st1:.*]] = llvm.mul %{{.*}}, %[[N]] : !llvm.i64
-// CHECK-NEXT: %[[st0:.*]] = llvm.mul %{{.*}}, %[[c42]] : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[M]], %{{.*}}[3, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st0]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[c42]], %{{.*}}[3, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st1]], %{{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[3, 2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st2]], %{{.*}}[4, 2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[st0]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[one]], %{{.*}}[4, 2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
%0 = alloc(%arg0, %arg1) : memref<?x42x?xf32>
// CHECK-NEXT: llvm.return %{{.*}} : !llvm.struct<(ptr<float>, ptr<float>, i64, array<3 x i64>, array<3 x i64>)>
return %0 : memref<?x42x?xf32>
// CHECK-LABEL: func @dynamic_alloc(
// CHECK: %[[M:.*]]: !llvm.i64, %[[N:.*]]: !llvm.i64) -> !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)> {
func @dynamic_alloc(%arg0: index, %arg1: index) -> memref<?x?xf32> {
-// CHECK: %[[sz:.*]] = llvm.mul %[[M]], %[[N]] : !llvm.i64
-// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.mul %[[sz]], %[[sizeof]] : !llvm.i64
+// CHECK-NEXT: %[[sz:.*]] = llvm.mul %[[N]], %[[M]] : !llvm.i64
+// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// CHECK-NEXT: llvm.call @malloc(%[[sz_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// CHECK-NEXT: llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// CHECK-NEXT: llvm.mlir.undef : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: %[[off:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[off]], %{{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
-// CHECK-NEXT: %[[st1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[st0:.*]] = llvm.mul %{{.*}}, %[[N]] : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[M]], %{{.*}}[3, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st0]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[3, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st1]], %{{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[one]], %{{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
%0 = alloc(%arg0, %arg1) : memref<?x?xf32>
// CHECK-NEXT: llvm.return %{{.*}} : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
return %0 : memref<?x?xf32>
// CHECK-LABEL: func @dynamic_alloca
// CHECK: %[[M:.*]]: !llvm.i64, %[[N:.*]]: !llvm.i64) -> !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)> {
func @dynamic_alloca(%arg0: index, %arg1: index) -> memref<?x?xf32> {
-// CHECK: %[[num_elems:.*]] = llvm.mul %[[M]], %[[N]] : !llvm.i64
+// CHECK-NEXT: %[[st1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
+// CHECK-NEXT: %[[num_elems:.*]] = llvm.mul %[[N]], %[[M]] : !llvm.i64
// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.mul %[[num_elems]], %[[sizeof]] : !llvm.i64
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[sz_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// CHECK-NEXT: %[[allocated:.*]] = llvm.alloca %[[sz_bytes]] x !llvm.float : (!llvm.i64) -> !llvm.ptr<float>
// CHECK-NEXT: llvm.mlir.undef : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[allocated]], %{{.*}}[0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[allocated]], %{{.*}}[1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: %[[off:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[off]], %{{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
-// CHECK-NEXT: %[[st1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[st0:.*]] = llvm.mul %{{.*}}, %[[N]] : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[M]], %{{.*}}[3, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
-// CHECK-NEXT: llvm.insertvalue %[[st0]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[3, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
+// CHECK-NEXT: llvm.insertvalue %[[N]], %{{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK-NEXT: llvm.insertvalue %[[st1]], %{{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
%0 = alloca(%arg0, %arg1) : memref<?x?xf32>
func @stdlib_aligned_alloc(%N : index) -> memref<32x18xf32> {
// ALIGNED-ALLOC-NEXT: %[[sz1:.*]] = llvm.mlir.constant(32 : index) : !llvm.i64
// ALIGNED-ALLOC-NEXT: %[[sz2:.*]] = llvm.mlir.constant(18 : index) : !llvm.i64
-// ALIGNED-ALLOC-NEXT: %[[num_elems:.*]] = llvm.mul %0, %1 : !llvm.i64
-// ALIGNED-ALLOC-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// ALIGNED-ALLOC-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// ALIGNED-ALLOC-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// ALIGNED-ALLOC-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// ALIGNED-ALLOC-NEXT: %[[bytes:.*]] = llvm.mul %[[num_elems]], %[[sizeof]] : !llvm.i64
+// ALIGNED-ALLOC-NEXT: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : !llvm.i64
+// ALIGNED-ALLOC-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
+// ALIGNED-ALLOC-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// ALIGNED-ALLOC-NEXT: %[[bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// ALIGNED-ALLOC-NEXT: %[[alignment:.*]] = llvm.mlir.constant(32 : index) : !llvm.i64
// ALIGNED-ALLOC-NEXT: %[[allocated:.*]] = llvm.call @aligned_alloc(%[[alignment]], %[[bytes]]) : (!llvm.i64, !llvm.i64) -> !llvm.ptr<i8>
// ALIGNED-ALLOC-NEXT: llvm.bitcast %[[allocated]] : !llvm.ptr<i8> to !llvm.ptr<float>
// CHECK-LABEL: func @zero_d_alloc() -> !llvm.struct<(ptr<float>, ptr<float>, i64)> {
// BAREPTR-LABEL: func @zero_d_alloc() -> !llvm.ptr<float> {
func @zero_d_alloc() -> memref<f32> {
-// CHECK-NEXT: llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
+// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: llvm.mul %{{.*}}, %[[sizeof]] : !llvm.i64
-// CHECK-NEXT: llvm.call @malloc(%{{.*}}) : (!llvm.i64) -> !llvm.ptr<i8>
+// CHECK-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
+// CHECK-NEXT: llvm.call @malloc(%[[size_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// CHECK-NEXT: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// CHECK-NEXT: llvm.mlir.undef : !llvm.struct<(ptr<float>, ptr<float>, i64)>
// CHECK-NEXT: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr<float>, ptr<float>, i64)>
// CHECK-NEXT: %[[c0:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[c0]], %{{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64)>
-// BAREPTR-NEXT: llvm.mlir.constant(1 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// BAREPTR-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
+// BAREPTR-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
// BAREPTR-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// BAREPTR-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// BAREPTR-NEXT: llvm.mul %{{.*}}, %[[sizeof]] : !llvm.i64
-// BAREPTR-NEXT: llvm.call @malloc(%{{.*}}) : (!llvm.i64) -> !llvm.ptr<i8>
+// BAREPTR-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
+// BAREPTR-NEXT: llvm.call @malloc(%[[size_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// BAREPTR-NEXT: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// BAREPTR-NEXT: llvm.mlir.undef : !llvm.struct<(ptr<float>, ptr<float>, i64)>
// BAREPTR-NEXT: llvm.insertvalue %[[ptr]], %{{.*}}[0] : !llvm.struct<(ptr<float>, ptr<float>, i64)>
// CHECK-LABEL: func @aligned_1d_alloc(
// BAREPTR-LABEL: func @aligned_1d_alloc(
func @aligned_1d_alloc() -> memref<42xf32> {
-// CHECK: llvm.mlir.constant(42 : index) : !llvm.i64
+// CHECK-NEXT: %[[sz1:.*]] = llvm.mlir.constant(42 : index) : !llvm.i64
+// CHECK-NEXT: %[[st1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: llvm.mul %{{.*}}, %[[sizeof]] : !llvm.i64
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz1]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// CHECK-NEXT: %[[alignment:.*]] = llvm.mlir.constant(8 : index) : !llvm.i64
-// CHECK-NEXT: %[[allocsize:.*]] = llvm.add {{.*}}, %[[alignment]] : !llvm.i64
+// CHECK-NEXT: %[[allocsize:.*]] = llvm.add %[[size_bytes]], %[[alignment]] : !llvm.i64
// CHECK-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[allocsize]]) : (!llvm.i64) -> !llvm.ptr<i8>
// CHECK-NEXT: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// CHECK-NEXT: %[[allocatedAsInt:.*]] = llvm.ptrtoint %[[ptr]] : !llvm.ptr<float> to !llvm.i64
// CHECK-NEXT: %[[c0:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK-NEXT: llvm.insertvalue %[[c0]], %{{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<1 x i64>, array<1 x i64>)>
-// BAREPTR-NEXT: llvm.mlir.constant(42 : index) : !llvm.i64
+// BAREPTR-NEXT: %[[sz1:.*]] = llvm.mlir.constant(42 : index) : !llvm.i64
+// BAREPTR-NEXT: %[[st1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// BAREPTR-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// BAREPTR-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// BAREPTR-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// BAREPTR-NEXT: llvm.mul %{{.*}}, %[[sizeof]] : !llvm.i64
+// BAREPTR-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[sz1]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// BAREPTR-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
// BAREPTR-NEXT: %[[alignment:.*]] = llvm.mlir.constant(8 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[allocsize:.*]] = llvm.add {{.*}}, %[[alignment]] : !llvm.i64
+// BAREPTR-NEXT: %[[allocsize:.*]] = llvm.add %[[size_bytes]], %[[alignment]] : !llvm.i64
// BAREPTR-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[allocsize]]) : (!llvm.i64) -> !llvm.ptr<i8>
// BAREPTR-NEXT: %[[ptr:.*]] = llvm.bitcast %{{.*}} : !llvm.ptr<i8> to !llvm.ptr<float>
// BAREPTR-NEXT: %[[allocatedAsInt:.*]] = llvm.ptrtoint %[[ptr]] : !llvm.ptr<float> to !llvm.i64
// CHECK-LABEL: func @static_alloc() -> !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)> {
// BAREPTR-LABEL: func @static_alloc() -> !llvm.ptr<float> {
func @static_alloc() -> memref<32x18xf32> {
-// CHECK: %[[sz1:.*]] = llvm.mlir.constant(32 : index) : !llvm.i64
-// CHECK-NEXT: %[[sz2:.*]] = llvm.mlir.constant(18 : index) : !llvm.i64
-// CHECK-NEXT: %[[num_elems:.*]] = llvm.mul %0, %1 : !llvm.i64
+// CHECK: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : !llvm.i64
// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: %[[bytes:.*]] = llvm.mul %[[num_elems]], %[[sizeof]] : !llvm.i64
-// CHECK-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
+// CHECK-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[size_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// CHECK-NEXT: llvm.bitcast %[[allocated]] : !llvm.ptr<i8> to !llvm.ptr<float>
-// BAREPTR-NEXT: %[[sz1:.*]] = llvm.mlir.constant(32 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[sz2:.*]] = llvm.mlir.constant(18 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[num_elems:.*]] = llvm.mul %[[sz1]], %[[sz2]] : !llvm.i64
+// BAREPTR: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : !llvm.i64
// BAREPTR-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// BAREPTR-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// BAREPTR-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// BAREPTR-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// BAREPTR-NEXT: %[[bytes:.*]] = llvm.mul %[[num_elems]], %[[sizeof]] : !llvm.i64
-// BAREPTR-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
+// BAREPTR-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// BAREPTR-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
+// BAREPTR-NEXT: %[[allocated:.*]] = llvm.call @malloc(%[[size_bytes]]) : (!llvm.i64) -> !llvm.ptr<i8>
// BAREPTR-NEXT: llvm.bitcast %[[allocated]] : !llvm.ptr<i8> to !llvm.ptr<float>
%0 = alloc() : memref<32x18xf32>
return %0 : memref<32x18xf32>
func @static_alloca() -> memref<32x18xf32> {
// CHECK-NEXT: %[[sz1:.*]] = llvm.mlir.constant(32 : index) : !llvm.i64
// CHECK-NEXT: %[[sz2:.*]] = llvm.mlir.constant(18 : index) : !llvm.i64
-// CHECK-NEXT: %[[num_elems:.*]] = llvm.mul %0, %1 : !llvm.i64
+// CHECK-NEXT: %[[st2:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
+// CHECK-NEXT: %[[num_elems:.*]] = llvm.mlir.constant(576 : index) : !llvm.i64
// CHECK-NEXT: %[[null:.*]] = llvm.mlir.null : !llvm.ptr<float>
-// CHECK-NEXT: %[[one:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
-// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[one]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
-// CHECK-NEXT: %[[sizeof:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
-// CHECK-NEXT: %[[bytes:.*]] = llvm.mul %[[num_elems]], %[[sizeof]] : !llvm.i64
-// CHECK-NEXT: %[[allocated:.*]] = llvm.alloca %[[bytes]] x !llvm.float : (!llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[gep:.*]] = llvm.getelementptr %[[null]][%[[num_elems]]] : (!llvm.ptr<float>, !llvm.i64) -> !llvm.ptr<float>
+// CHECK-NEXT: %[[size_bytes:.*]] = llvm.ptrtoint %[[gep]] : !llvm.ptr<float> to !llvm.i64
+// CHECK-NEXT: %[[allocated:.*]] = llvm.alloca %[[size_bytes]] x !llvm.float : (!llvm.i64) -> !llvm.ptr<float>
%0 = alloca() : memref<32x18xf32>
// Test with explicitly specified alignment. llvm.alloca takes care of the
func @get_gv0_memref() {
%0 = get_global_memref @gv0 : memref<2xf32>
// CHECK: %[[DIM:.*]] = llvm.mlir.constant(2 : index) : !llvm.i64
+ // CHECK: %[[STRIDE:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @gv0 : !llvm.ptr<array<2 x float>>
// CHECK: %[[ZERO:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ADDR]][%[[ZERO]], %[[ZERO]]] : (!llvm.ptr<array<2 x float>>, !llvm.i64, !llvm.i64) -> !llvm.ptr<float>
// CHECK: llvm.insertvalue %[[GEP]], {{.*}}[1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<1 x i64>, array<1 x i64>)>
// CHECK: %[[OFFSET:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[OFFSET]], {{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<1 x i64>, array<1 x i64>)>
- // CHECK: %[[STRIDE:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[DIM]], {{.*}}[3, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<1 x i64>, array<1 x i64>)>
// CHECK: llvm.insertvalue %[[STRIDE]], {{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<1 x i64>, array<1 x i64>)>
return
func @get_gv2_memref() {
// CHECK: %[[DIM0:.*]] = llvm.mlir.constant(2 : index) : !llvm.i64
// CHECK: %[[DIM1:.*]] = llvm.mlir.constant(3 : index) : !llvm.i64
+ // CHECK: %[[STRIDE1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @gv2 : !llvm.ptr<array<2 x array<3 x float>>>
// CHECK: %[[ZERO:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ADDR]][%[[ZERO]], %[[ZERO]], %[[ZERO]]] : (!llvm.ptr<array<2 x array<3 x float>>>, !llvm.i64, !llvm.i64, !llvm.i64) -> !llvm.ptr<float>
// CHECK: llvm.insertvalue %[[GEP]], {{.*}}[1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK: %[[OFFSET:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[OFFSET]], {{.*}}[2] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
- // CHECK: %[[STRIDE1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
- // CHECK: %[[STRIDE0:.*]] = llvm.mlir.constant(3 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[DIM0]], {{.*}}[3, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
- // CHECK: llvm.insertvalue %[[STRIDE0]], {{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK: llvm.insertvalue %[[DIM1]], {{.*}}[3, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
+ // CHECK: llvm.insertvalue %[[DIM1]], {{.*}}[4, 0] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
// CHECK: llvm.insertvalue %[[STRIDE1]], {{.*}}[4, 1] : !llvm.struct<(ptr<float>, ptr<float>, i64, array<2 x i64>, array<2 x i64>)>
%0 = get_global_memref @gv2 : memref<2x3xf32>