# Compiler mis-recognizes contiguous reinterpreted matrices?

**URL:** <https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979>\
**Category:** General Usage\
**Tags:** linearalgebra, memory, sciml, differentialequation\
**Created:** [August 21, 2026, 5:54pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979 "2026-08-21T17:54:13Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)\
**Post date:** [August 21, 2026, 5:54pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/1 "2026-08-21T17:54:14Z")

</div>

I am implementing an ODE to use with `OrdinaryDiffEq`. I am simultaneously evolving in time multiple quantities, which are combinations of vectors and matrices, some real and some complex. The approach I took has been to group them all in a long `Vector{Float64}` and and my function `f!(du, u, p ,t)` which computes derivates, I slice into that long vector. However, I noticed that this leads to poor matrix-matrix multiplication performance on the obtained slices for some methods of slicing. I tracked down the issue to the fact `gemm` is not called for certain matrix types, though it seems that it should be possible. A MWE is the following:

```julia
v1 = rand(Float64, 100);
v2 = reinterpret(ComplexF64, v1);
x1 = view(v2, 1:20);
x2 = reshape(view(v2, 1:20), 4, 5);
isa.((x1, x2), StridedVecOrMat)
# (true, false)

```

This suggests that though `x2` and `x1` refer to the same contiguous memory, the compiler cannot reason that `x2` is such, and thus calls generic matmul methods instead of `gemm`. Can this be considered a bug? Is there a better way to annotate the types?

(I do have a temporary workaround: first slice into the float vector, then reinterpret. Is there a rule of thumb to know when these operations do not "commute?)

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [August 21, 2026, 6:11pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/2 "2026-08-21T18:11:05Z")

</div>

This could be fixed by Julia having strided array traits:

> <https://github.com/JuliaLang/julia/pull/60964>
>
> This is an alternative to #60894 and #61807
> 
> It adds new trait functions to th…e strided array interface.
> 
> These functions map an array type to a Bool.
> 
> The main trait is \`is\_strided\` which marks if all arrays of a type follow the strided array interface.
> 
> \`is\_contiguous\` marks that an array type is using the same memory layout as \`Array\`.
> Implementing \`is\_contiguous\` as true also opts into default definitions for \`elsize\` and \`strides\` to make it easier to define a new strided array type.
> 
> \`is\_vec\_strided\` exists as a way to mark that a reshaped array will remain strided.
> 
> \`is\_ptr\_loadable\` and \`is\_ptr\_storable\` can be used to check if a pointer to an array element can be used to get or set the value.
> 
> The \`has\_vec\_strided\_layout\` and \`has\_contiguous\_layout\` exist to avoid infinite loops or method ambiguities in this system.
> These variants are used to check the trait while also handling the zero and one dimensional cases.
> 
> Created with assistance of generative AI
> 
> closes #54715 #59435 #10889

```julia-repl
julia> Base.is_contiguous(typeof(x2))
true

julia> Base.is_contiguous(typeof(x1))
true

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 21, 2026, 6:29pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/3 "2026-08-21T18:29:17Z")

</div>

> [@bremez](#):
>
> This suggests that though `x2` and `x1` refer to the same contiguous memory, the compiler cannot reason that `x2` is such, and thus calls generic matmul methods instead of `gemm`.

It’s not a limitation of the compiler, it’s a limitation of how the `StridedArray` type is defined [here](https://github.com/JuliaLang/julia/blob/6e5229a469837f676577a91076000e4869cc35ae/base/reinterpretarray.jl#L193-L202).

`x1` is a `StridedVector` because it is a `StridedSubArray`, which includes a `SubArray` of a `StridedReinterpretArray` such as `v2`.

However, the `ReshapedArray`, `x2`, is _not_ a `StridedReshapedArray` because that definition does _not_ include reshaped arrays made from a `SubArray` of a reinterpreted array, only subarrays of `DenseArray`.

The basic problem here is that these types are defined as a hierarchy and couldn’t be mutually recursive (until recently, at least?), which is what you would really want here for a `StridedArray` type (e.g. a `StridedArray` should include any strided subarray of any `StridedArray`). Perhaps this could be fixed by the [new `typegroup` facility in Julia 1.14](https://github.com/JuliaLang/julia/pull/60569)?

A trait would give more flexibility, I guess.

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [August 21, 2026, 7:44pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/4 "2026-08-21T19:44:52Z")

</div>

Yes, the main flexibility a trait gives is for array types not part of Base. Since the `StridedArray` type is defined in Base it can only reference other types defined in Base.

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [August 22, 2026, 7:15am UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/5 "2026-08-22T07:15:44Z")

</div>

Is it possible to abuse Array constructor from pointer to make a view as separate array?  
IIRC, the docs say to not do that, but are there real implications if the view has a limited scope and the parent (or maybe “donor” would be more fitting for such a case) is not resized?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 22, 2026, 10:48am UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/6 "2026-08-22T10:48:25Z")

</div>

> [@Vasily\_Pisarev](#):
>
> Is it possible to abuse Array constructor from pointer to make a view as separate array?

Yes:

```julia-auto
julia> x3 = unsafe_wrap(Array, pointer(v2), (4, 5));

julia> x3 == x2
true

julia> x3 isa StridedMatrix
true

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [August 22, 2026, 10:54am UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/7 "2026-08-22T10:54:56Z")

</div>

You can also use `Base.wrap` to wrap the memory of some vector:

```julia-auto
julia> v = float.(1:8);

julia> Base.wrap(Array, v.ref, (2, 4))
2×4 Matrix{Float64}:
 1.0 3.0 5.0 7.0
 2.0 4.0 6.0 8.0

```

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [August 22, 2026, 12:44pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/8 "2026-08-22T12:44:49Z")

</div>

> [@Vasily\_Pisarev](#):
>
> are there real implications if the view has a limited scope

Yes, using `unsafe_wrap` to make two `Memory` with different eltypes alias is very much undefined behavior, so IIUC julia may give LLVM nonsense input. If LLVM gets nonsense input it is hard to predict exactly what could go wrong.

---

<div class="post-metadata">

**Author:** ![nhz2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nhz2/32/44428_2.png) [@nhz2](https://discourse.julialang.org/u/nhz2)\
**Post date:** [August 22, 2026, 12:47pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/9 "2026-08-22T12:47:57Z")

</div>

But also it doesn’t have to be that way. Maybe in a future version of Julia using `unsafe_wrap` like that is fine.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 22, 2026, 1:53pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/10 "2026-08-22T13:53:25Z")

</div>

> [@nhz2](#):
>
> Yes, using `unsafe_wrap` to make two `Memory` with different eltypes alias is very much undefined behavior,

This is not two arbitrary eltypes, however, but rather `Float64` and `ComplexF64`, and the relationship between their memory layouts is known and should not change (many, many things rely on this; that’s why e.g. C and C++ included it in their standards).

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [August 22, 2026, 2:44pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/11 "2026-08-22T14:44:45Z")

</div>

I think @nhz2 is referring to how it can break TBAA (type based alias analysis), not the potential for layout differences.

`unsafe_load` and `unsafe_store!` disable TBAA in the function body they’re used in to defend against the sort of problems that can be caused here, but I’m not sure if `unsafe_wrap` would do the same or not.

* * *

Edit: from the docstring of `unsafe_wrap`:

> Unlike `unsafe_load` and `unsafe_store!`, the programmer is responsible also for ensuring that the underlying data is not accessed through two arrays of different element type, similar to the strict aliasing rule in C.

So if you want to use the pointer to convert between arrays of Floats / ComplexFloats, you’ll need to use a special array type that unsafe\_loads / unsafe\_stores.

---

<div class="post-metadata">

**Author:** ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)\
**Post date:** [August 25, 2026, 2:02pm UTC](https://discourse.julialang.org/t/compiler-mis-recognizes-contiguous-reinterpreted-matrices/138979/12 "2026-08-25T14:02:33Z")

</div>

Perhaps an alternative solution is if SciML/OrdinaryDiffEq can co-evolve multiple quantities? i.e. if `f!(du, u, p, t)` can be implemented for `u::Tuple` of concrete array types? I’m not sure how then to feed this structure to the integrator in `OrdinaryDiffEq.solve`.
