LLVM Discussion Forums

How to allocate a memref with non-strided affine_map

I want to allocate a memref with non-strided affine_map as follows, and have got an error with “Non-strided layout maps must have been normalized away”. It is no problem for us to normalize the shape before calling std.alloc, but it generates a normalized memref. Because I want to get a memref keeping the original memref shape and affine_map information, a simple normalization way does not work for me.

Can some one teach me a way to get a memref with non-strided affine_map?
(1) It seems that the current std.alloc does not support the following example. Is my understanding right?
(2) Can we have a chance to create a patch to extend the std.alloc to support it? Or we should not do so?
(3) Are there other ways to get a “memref with non-strided affine_map”? For example, can we get one from another memref by a kind of “casting” technique (like “.cast<…>” or "MemRefCastOp)?

#map0 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2 floordiv 32, d3 floordiv 64, d2 mod 32, d3 mod 64)>
module {func @test_alloc_affine() -> memref<1x16x14x14xf32, #map0> {
    %0 = alloc() : memref<1x16x14x14xf32, #map0>
     return %0 : memref<1x16x14x14xf32, #map0>}}

The error you’re mentioning (“Non-strided layout maps must have been normalized away”) is an assertion in the lowering to LLVM.
Indeed there is no runtime representation for such a memref, I think it is only OK as an intra-procedural value that you can operate on and it requires to be rewritten (using the -lower-affine pass I believe) before converting to LLVM.

Please use -simplify-affine-structures on it, which uses normalizeMemRef to turn memrefs into ones with identity layout maps (rewriting any load/stores). In this case, normalizeMemRef would bail out since it’s not yet an inter-procedural utility (it won’t rewrite when such memrefs are function arguments / return values or are used in a non-dereferencing context).

Thanks, it works with the alloc / dealloc in the same function, which is luckily the case we need.

#map0 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2 floordiv 32, d3 floordiv 64, d2 mod 32, d3 mod 64)>
module {
    func @test_alloc_affine() -> () {
        %0 = alloc() : memref<1x16x14x14xf32, #map0>
        dealloc %0 :  memref<1x16x14x14xf32, #map0>
     return
     }
}

becomes with -simplify-affine-structures

module {
  func @test_alloc_affine() {
    %0 = alloc() : memref<1x16x1x1x32x64xf32>
    dealloc %0 : memref<1x16x1x1x32x64xf32>
    return
  }
}
2 Likes

Please see here: https://reviews.llvm.org/D84490 It doesn’t handle one of the return value cases but otherwise covers most interprocedural ones.

Thank you for your useful answer. I understand that we cannot lower memref with non-strided afffine_map cannot be lowered by a standard lowering pass. I will use it as an internal representation only, and will lower it after simplification.

@bondhugula, @AlexEichenberger Thank your your information. I will use memref with non-strided affine_map as an internal value at a certain level, and will normalize and lower it later by the shown method. Thank you.