14634 Commits

Author SHA1 Message Date
Quinn Dawkins
6067129fbe
Revert "[mlir][vector] Add a pattern to fuse extract(constant_mask) (#81057)" (#83275)
This reverts commit 5cdb8c0c8854d08ac7ca131ce3e8d78a32eb6716.

This pattern is producing incorrect IR. For example,

```mlir
func.func @extract_subvector_from_constant_mask() -> vector<16xi1> {
  %mask = vector.constant_mask [2, 3] : vector<16x16xi1>
  %extract = vector.extract %mask[8] : vector<16xi1> from vector<16x16xi1>
  return %extract : vector<16xi1>
}
```

Canonicalizes to

```mlir
func.func @extract_subvector_from_constant_mask() -> vector<16xi1> {
  %0 = vector.constant_mask [3] : vector<16xi1>
  return %0 : vector<16xi1>
}
```

Where it should be a zero mask because the extraction index (8) is
greater than the constant mask size along that dim (2).
2024-02-28 10:52:57 -05:00
Michael Liao
a8364c9e17 [mlir] Fix shared builds. NFC 2024-02-28 09:31:05 -05:00
Ingo Müller
5f2097dbed
[mlir] Expose MLIR_CUDA_CONVERSIONS_ENABLED in mlir-config.h. (#83004)
That macro was not defined in some cases and thus yielded warnings if
compiled with `-Wundef`. In particular, they were not defined in the
BUILD files, so the GPU targets were broken when built with Bazel. This
commit exposes mentioned CMake variable through mlir-config.h and uses
the macro that is introduced with the same name. This replaces the macro
MLIR_CUDA_CONVERSIONS_ENABLED, which the CMake files previously defined
manually.
2024-02-28 14:48:40 +01:00
Tobias Gysi
e39e30e952
[mlir][llvm] Fix access group translation (#83257)
This commit fixes the translation of access group metadata to LLVM IR.
Previously, it did not use a temporary metadata node to model the
placeholder of the self-referencing access group nodes. This is
dangerous since, the translation may produce a metadata list with a null
entry that is later on changed changed with a self reference. At the
same time, for example the debug info translation may create the same
uniqued node, which after setting the self-reference the suddenly
references the access group metadata. The commit avoids such breakages.
2024-02-28 14:45:18 +01:00
Rishabh Bali
915fce0402
[mlir][affine] Enable ConvertAffineToStandard pass to handle affine.delinearize_index Op. (#82189)
This PR, aims to enable the `ConvertAffineToStandard` to handle
`affine.dilinearize_index` Operation.

Fixes #78458
2024-02-28 18:58:53 +05:30
Matthias Springer
926a19bf0b
[mlir][Transforms][NFC] Remove SplitBlockRewrite (#82777)
When splitting a block during a dialect conversion, a
`SplitBlockRewrite` object is stored in the dialect conversion state.
This commit removes `SplitBlockRewrite`. Instead, a combination of
`CreateBlockRewrite` and multiple `MoveOperationRewrite` is used.

This change simplifies the internal state of the dialect conversion and
is also needed to properly support listeners.

`RewriteBase::splitBlock` is now no longer virtual. All necessary
information for committing/rolling back a split block rewrite can be
deduced from `Listener::notifyBlockInserted` and
`Listener::notifyOperationInserted` (which is also called when moving an
operation).
2024-02-28 14:26:02 +01:00
Oleksandr "Alex" Zinenko
5468f88413
[mlir] update remaining transform tests to main pass (#81279)
Use the main transform interpreter pass instead of the test pass. The
only tests that are not updated are specific to the operation of the
test pass.
2024-02-28 11:06:53 +01:00
Matthias Springer
6008cd40b7
[mlir][Transforms] Dialect conversion: Assert when accessing erased ops (#83132)
The dialect conversion maintains sets of "ignored" and "replaced" ops.
This change simplifies the two sets, such that all nested ops are
included. (This was previously not the case and sometimes only the
parent op was included.)

This change allows for more aggressive assertions to prevent incorrect
rewriter API usage. E.g., accessing ops/blocks/regions within an erased
op.

A concrete example: I have seen conversion patterns in downstream
projects where an op is replaced with a new op, and the region of the
old op is afterwards inlined into the newly created op. This is invalid
rewriter API usage: ops that were replaced/erased should not be
accessed. Nested ops will be considered "ignored", even if they are
moved to a different region after the region's parent op was erased
(which is illegal API usage). Instead, create a new op, inline the
regions, then replace the old op with the new op.
2024-02-28 10:22:45 +01:00
Quinn Dawkins
c2b952926f
[mlir][vector] Fix n-d transfer write distribution (#83215)
Currently n-d transfer write distribution can be inconsistent with
distribution of reductions if a value has multiple users, one of which
is a transfer_write with a non-standard distribution map, and the other
of which is a vector.reduction.

We may want to consider removing the distribution map functionality in
the future for this reason.
2024-02-28 00:11:28 -05:00
erman-gurses
87c0260f45
[AMDGPU] Add parameterization for optimized shared memory variables (#82508)
- This PR adds parameterization for shared memory variables that are
used for optimization: `sharedMemoryLineSizeBytes` and
`defaultVectorSizeBits.`
- The default values are set to 128 for both variables since it gives
zero bank conflicts.
2024-02-27 23:28:12 -05:00
Kareem Ergawy
9d56be010c
[MLIR][OpenMP] Support basic materialization for omp.private ops (#81715)
Adds basic support for materializing delayed privatization. So far, the
restrictions on the implementation are:
- Only `private` clauses are supported (`firstprivate` support will be
  added in a later PR).
2024-02-28 05:00:07 +01:00
Diego Caballero
9d0acb872a
[mlir][Vector] Add support for trunci to narrow type emulation (#82565)
This PR add support for `arith.trunci` to vector narrow type emulation for iX -> i4 truncations, for X >= 8. For now, the pattern only works for 1D vectors and is based on `vector.shuffle` ops. We would need `vector.deinterleave` to add n-D vector support.
2024-02-27 15:27:31 -08:00
Peiming Liu
d82e93e7f1
[mlir][sparse] add merger support on Batch LevelType. (#83186) 2024-02-27 13:18:43 -08:00
Peiming Liu
0d1f95760b
[mlir][sparse] support type conversion from batched sparse tensors to… (#83163)
… memrefs.
2024-02-27 12:05:28 -08:00
Krzysztof Drewniak
563f414e04
[mlir][AMDGPU] Set uniform-work-group-size=true by default (#79077)
GPU kernels generated via typical MLIR mechanisms make the assumption
that all workgroups are of uniform size, and so, as in OpenMP, it is
appropriate to set the "uniform-work-group-size"="true" attribute on
these functions by default. This commit makes that choice.

In the event it is needed, this commit adds
`rocdl.uniform_work_group_size` as an attribute to be set on LLVM
functions that can be used to override the default.

In addition, add proper failure messages to translation
2024-02-27 12:35:48 -06:00
Krzysztof Drewniak
4cba5957e6
[mlir][ROCDL] Set the LLVM data layout when lowering to ROCDL LLVM (#74501)
In order to ensure operations lower correctly (especially
memref.addrspacecast, which relies on the data layout benig set
correctly then dealing with dynamic memrefs) and to prevent compilation
issues later down the line, set the `llvm.data_layout` attribute on GPU
modules when lowering their contents to a ROCDL / AMDGPU target.

If there's a good way to test the embedded string to prevent it from
going out of sync with the LLVM TargetMachine, I'd appreciate hearing
about it. (Or, alternatively, if there's a place I could farctor the
string out to).
2024-02-27 09:59:50 -06:00
Kai Sasaki
288d317fff
[mlir][complex] Support Fastmath flag in conversion of complex.div to standard (#82729)
Support Fastmath flag to convert `complex.div` to standard dialects. 

See:
https://discourse.llvm.org/t/rfc-fastmath-flags-support-in-complex-dialect/71981
2024-02-27 18:51:24 +09:00
Jie Fu
ef7417fbc5 [mlir] Fix -Wunused-but-set-variable in ModuleTranslation.cpp (NFC)
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp:1050:11:
error: variable 'numConstantsHit' set but not used [-Werror,-Wunused-but-set-variable]
      int numConstantsHit = 0;
          ^
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp:1051:11:
error: variable 'numConstantsErased' set but not used [-Werror,-Wunused-but-set-variable]
      int numConstantsErased = 0;
          ^
2 errors generated.
2024-02-27 10:37:17 +08:00
Xiang Li
c11627c2f4
[MLIR][LLVM] Fix memory explosion when converting global variable bodies in ModuleTranslation (#82708)
There is memory explosion when converting the body or initializer region
of a large global variable, e.g. a constant array.

For example, when translating a constant array of 100000 strings:

llvm.mlir.global internal constant @cats_strings() {addr_space = 0 :
i32, alignment = 16 : i64} : !llvm.array<100000 x ptr<i8>> {
    %0 = llvm.mlir.undef : !llvm.array<100000 x ptr<i8>>
    %1 = llvm.mlir.addressof @om_1 : !llvm.ptr<array<1 x i8>>
%2 = llvm.getelementptr %1[0, 0] : (!llvm.ptr<array<1 x i8>>) ->
!llvm.ptr<i8>
    %3 = llvm.insertvalue %2, %0[0] : !llvm.array<100000 x ptr<i8>>
    %4 = llvm.mlir.addressof @om_2 : !llvm.ptr<array<1 x i8>>
%5 = llvm.getelementptr %4[0, 0] : (!llvm.ptr<array<1 x i8>>) ->
!llvm.ptr<i8>
    %6 = llvm.insertvalue %5, %3[1] : !llvm.array<100000 x ptr<i8>>
    %7 = llvm.mlir.addressof @om_3 : !llvm.ptr<array<1 x i8>>
%8 = llvm.getelementptr %7[0, 0] : (!llvm.ptr<array<1 x i8>>) ->
!llvm.ptr<i8>
    %9 = llvm.insertvalue %8, %6[2] : !llvm.array<100000 x ptr<i8>>
    %10 = llvm.mlir.addressof @om_4 : !llvm.ptr<array<1 x i8>>
%11 = llvm.getelementptr %10[0, 0] : (!llvm.ptr<array<1 x i8>>) ->
!llvm.ptr<i8>
    %12 = llvm.insertvalue %11, %9[3] : !llvm.array<100000 x ptr<i8>>

    ... (ignore the remaining part)
}

where @om_1, @om_2, ... are string global constants.

Each time an operation is converted to LLVM, a new constant is created.
When it comes to llvm.insertvalue, a new constant array of 100000
elements is created and the old constant array (input) is not destroyed.
This causes memory explosion. We observed that, on a system with 128 GB
memory, the translation of 100000 elements got killed due to using up
all the memory. On a system with 64 GB, 65536 elements was enough to
cause the translation killed.

There is a previous patch (https://reviews.llvm.org/D148487) which fix
this issue but was reverted for
https://github.com/llvm/llvm-project/issues/62802

The old patch checks generated constants and destroyed them if there is
no use. But the check of use for the constant is too early, which cause
the constant be removed before use.


This new patch added a map was added a map to save expected use count
for a constant. Then decrease when reach each use.
And only erase the constant when the use count reach to zero

With new patch, the repro in
https://github.com/llvm/llvm-project/issues/62802 finished correctly.
2024-02-26 21:15:12 -05:00
Peiming Liu
56d58295dd
[mlir][sparse] Introduce batch level format. (#83082) 2024-02-26 16:08:28 -08:00
Matthias Springer
7b66b5d6c2
[mlir][Transforms] Track erased ops separately (#83051)
#83023 fixed a performance regression related to "ignored" ops. This
broke some downstream projects that access ops after they were replaced
(an API violation). This change restores the original behavior before
#83023 (but without the performance regression), to give downstream
users more time to fix their code.
2024-02-26 20:49:52 +01:00
Hsiangkai Wang
5cdb8c0c88
[mlir][vector] Add a pattern to fuse extract(constant_mask) (#81057)
This pattern will rewrite
ExtractOp(ConstantMaskOp) -> ConstantMaskOp
or
ExtractOp(ConstantMaskOp) -> Constant
2024-02-26 19:00:15 +00:00
Matthias Springer
45732b6454
[mlir][Transforms] Fix compile time regression in dialect conversion (#83023)
The dialect conversion does not directly erase ops that are
replaced/erased with a rewriter. Instead, the op stays in place and is
erased at the end if the dialect conversion succeeds. However, ops that
were replaced/erased are ignored from that point on.

#81757 introduced a compile time regression that made the check whether
an op is ignored or not more expensive. Whether an op is ignored or not
is queried many times throughout a dialect conversion, so the check must
be fast.

After this change, replaced ops are stored in the `ignoredOps` set. This
also simplifies the dialect conversion a bit.
2024-02-26 17:40:56 +01:00
Benjamin Maxwell
8cfb71613c
[mlir][ArmSME] Replace use of isa with isa_and_present (#82798)
`op` can be null here, in which case this should just return a null
value back.
2024-02-26 09:44:26 +00:00
Mehdi Amini
e5332482c6
[MLIR][Spirv] Use StringAttr for linkage_name (NFC) (#82953)
std::string was used here, likely by mistake. The usual convention for
attributes is to use StringAttr.
2024-02-25 20:47:08 -08:00
Matteo Franciolini
ce4da0c4ee
Enables textual IR roundtripping through --verifyRoundtrip (#82946)
The patch enables roundtrip to textual file when running
`--verifyRoundtrip`. The verification is successful if both textual and
bytecode formats can roundtrip successfully.
2024-02-25 20:34:56 -08:00
tw-ilson
1d5e3b2d65
[mlir][spirv] Use ODS generated attribute names for op definitions (#81552)
Since ODS generates getters functions for SPIRV operations' attribute
names, we replace instances of these hardcoded strings in the SPIR-V
dialect's op parser/printer with function calls for consistency.

Fixes https://github.com/llvm/llvm-project/issues/77627

---------

Co-authored-by: Lei Zhang <antiagainst@gmail.com>
2024-02-25 16:47:25 -08:00
Matteo Franciolini
da092e8808
Fix bytecode roundtrip of unregistered ops (#82932)
When roundtripping to bytecode an unregistered operation name that does
not contain any '.' separator, the bytecode writer will emit an op
encoding without a proper opName. In this case, the string just becomes
a possibly unknown dialect name. At parsing, this dialect name is
used as a proper operation name.

However, when the unregistered operation name coincidentally matches
that of a dialect, the parser would fail. That means we can't roundtrip
an unregistered op with a name that matches one of the registered
dialect names. For example,

```
"index"() : () -> ()
```

can be emitted but cannot be parsed, because its name is coincidentally
the same as that of the Index dialect. The patch removes such
inconsistency.

This patch specifically fixes the bytecode roundtrip of
`mlir/test/IR/parser.mlir`.
2024-02-25 16:18:42 -08:00
Quinn Dawkins
1e98d4883d
[mlir][linalg] NFC: Use tablegen macro for pass constructors (#82892)
This uses the tablegen macros for generating pass constructors, exposing
pass options for fold-unit-extent-dims and linalg-detensorize.

Additionally aligns some of the pass namings to their text counterpart.
This includes an API change:

createLinalgGeneralizationPass -> createLinalgGeneralizeNamedOpsPass
2024-02-24 14:35:39 -05:00
Matthias Springer
91d5653e3a
[mlir] Use OpBuilder::createBlock in op builders and patterns (#82770)
When creating a new block in (conversion) rewrite patterns,
`OpBuilder::createBlock` must be used. Otherwise, no
`notifyBlockInserted` notification is sent to the listener.

Note: The dialect conversion relies on listener notifications to keep
track of IR modifications. Creating blocks without the builder API can
lead to memory leaks during rollback.
2024-02-24 09:10:07 +01:00
Aart Bik
1c2456d659
[mlir][sparse] remove very thin header file from sparse runtime support (#82820) 2024-02-23 12:37:36 -08:00
Aart Bik
f8ce460e48
[mlir][sparse] cleanup sparse runtime library (#82807)
remove some obsoleted APIs from the library that have been fully
replaced with actual direct IR codegen
2024-02-23 10:52:28 -08:00
Benjamin Maxwell
1408667fdd [mlir][ArmSME] Follow MLIR constant style in VectorLegalization.cpp (NFC) 2024-02-23 16:55:32 +00:00
Matthias Springer
5840aa95e3
[mlir][Transforms] Fix crash in dialect conversion (#82783)
This is a follow-up to #82333. It is possible that the target block of a
`BlockTypeConversionRewrite` is detached, so the `MLIRContext` cannot be
taken from the block.
2024-02-23 17:26:39 +01:00
Matthias Springer
3b232f066d
[mlir][linalg] LinalgOp: Disallow mixed tensor/buffer semantics (#80660)
Related discussion:
https://github.com/llvm/llvm-project/pull/73908/files#r1414913030.

This change fixes #73547.
2024-02-23 15:52:26 +01:00
Matthias Springer
492e8ba038
[mlir] Fix memory leaks after #81759 (#82762)
This commit fixes memory leaks that were introduced by #81759. The way
ops and blocks are erased changed slightly.

The leaks were caused by an incorrect implementation of op builders:
blocks must be created with the supplied builder object. Otherwise, they
are not properly tracked by the dialect conversion and can leak during
rollback.
2024-02-23 14:28:57 +01:00
Johannes Reifferscheid
bcf9826a53
[MLIR] Expose approximation patterns for tanh/erf. (#82750)
These patterns can already be used via
populateMathPolynomialApproximationPatterns, but that includes a number
of other patterns that may not be needed.

There are already similar functions for expansion.

For now only adding tanh and erf since I have a concrete use case for
these two.
2024-02-23 13:15:08 +01:00
Matthias Springer
7bb08ee826
[mlir][Transforms][NFC] Decouple ConversionPatternRewriterImpl from ConversionPatternRewriter (#82333)
`ConversionPatternRewriterImpl` no longer maintains a reference to the
respective `ConversionPatternRewriter`. An `MLIRContext` is sufficient.
This commit simplifies the internal state of
`ConversionPatternRewriterImpl`.
2024-02-23 11:55:24 +01:00
Matthias Springer
5f1319bb38
[mlir][Transforms] Encapsulate dialect conversion options in ConversionConfig (#82250)
This commit adds a new `ConversionConfig` struct that allows users to
customize the dialect conversion. This configuration is similar to
`GreedyRewriteConfig` for the greedy pattern rewrite driver.

A few existing options are moved to this objects, simplifying the
dialect conversion API.
2024-02-23 11:28:05 +01:00
Benjamin Maxwell
78890904c4
[mlir][math] Propagate scalability in convert-math-to-llvm (#82635)
This also generally increases the coverage of scalable vector types in
the math-to-llvm tests.
2024-02-23 09:48:58 +00:00
Matthias Springer
a622b21f46
[mlir][Transforms] Make ConversionPatternRewriter constructor private (#82244)
`ConversionPatternRewriter` objects should not be constructed outside of
dialect conversions. Some IR modifications performed through a
`ConversionPatternRewriter` are reflected in the IR in a delayed fashion
(e.g., only when the dialect conversion is guaranteed to succeed). Using
a `ConversionPatternRewriter` outside of the dialect conversion is
incorrect API usage and can bring the IR in an inconsistent state.

Migration guide: Use `IRRewriter` instead of
`ConversionPatternRewriter`.
2024-02-23 10:31:55 +01:00
Tobias Gysi
335d34d9ea
[MLIR][LLVM] Fix debug intrinsic import (#82637)
This revision handles the case that the translation of a scope fails due
to cyclic metadata. This mainly affects the import of debug intrinsics
that indirectly take such a scope as metadata argument (e.g. via local
variable or label metadata). This commit ensures we drop intrinsics with
such a dependency on cyclic metadata.
2024-02-23 10:30:19 +01:00
Matthias Springer
59ff4d131c
[mlir][Transforms][NFC] Turn unresolved materializations into IRRewrites (#81761)
This commit is a refactoring of the dialect conversion. The dialect
conversion maintains a list of "IR rewrites" that can be committed (upon
success) or rolled back (upon failure).

This commit turns the creation of unresolved materializations
(`unrealized_conversion_cast`) into `IRRewrite` objects. After this
commit, all steps in `applyRewrites` and `discardRewrites` are calls to
`IRRewrite::commit` and `IRRewrite::rollback`.
2024-02-23 10:15:12 +01:00
Matthias Springer
9ca70d72f4
[mlir][Transforms][NFC] Turn op creation into IRRewrite (#81759)
This commit is a refactoring of the dialect conversion. The dialect
conversion maintains a list of "IR rewrites" that can be committed (upon
success) or rolled back (upon failure).

Until now, the dialect conversion kept track of "op creation" in
separate internal data structures. This commit turns "op creation" into
an `IRRewrite` that can be committed and rolled back just like any other
rewrite. This commit simplifies the internal state of the dialect
conversion.
2024-02-23 10:03:26 +01:00
Matthias Springer
d68d295161
[mlir][Transforms][NFC] Turn op/block arg replacements into IRRewrites (#81757)
This commit is a refactoring of the dialect conversion. The dialect
conversion maintains a list of "IR rewrites" that can be committed (upon
success) or rolled back (upon failure).

Until now, op replacements and block argument replacements were kept
track in separate data structures inside the dialect conversion. This
commit turns them into `IRRewrite`s, so that they can be committed or
rolled back just like any other rewrite. This simplifies the internal
state of the dialect conversion.

Overview of changes:
* Add two new rewrite classes: `ReplaceBlockArgRewrite` and
`ReplaceOperationRewrite`. Remove the `OpReplacement` helper class; it
is now part of `ReplaceOperationRewrite`.
* Simplify `RewriterState`: `numReplacements` and `numArgReplacements`
are no longer needed. (Now being kept track of by `numRewrites`.)
* Add `IRRewrite::cleanup`. Operations should not be erased in `commit`
because they may still be referenced in other internal state of the
dialect conversion (`mapping`). Detaching operations is fine.
* `trackedOps` are now updated during the "commit" phase instead of
after applying all rewrites.
2024-02-23 09:48:13 +01:00
Jerry-Ge
d57f158a95
[Tosa] Add Tosa Sin and Cos operators (#82510)
- Add Tosa Sin and Cos operators to the MLIR dialect
- Define the new Tosa_FloatTensor type

---------

Signed-off-by: Jerry Ge <jerry.ge@arm.com>
2024-02-22 15:54:42 -08:00
Diego Caballero
847048f497
[mlir][Vector] Fix bug in vector xfer op flattening transformation (#81964)
It looks like the affine map generated to compute the indices of the
collapsed dimensions used the wrong dim size. For indices `[idx0][idx1]`
we computed the collapsed index as `idx0*size0 + idx1` instead of
`idx0*size1 + idx1`. This led to correctness issues in convolution tests
when enabling this transformation internally.
2024-02-22 12:37:32 -08:00
Matthias Gehre
c1e9883a81
[TOSA] TosaToLinalg: fix int64_t min/max lowering of clamp (#82641)
tosa.clamp takes `min`/`max` attributes as i64, so ensure that the
lowering to linalg works for the whole range.

Co-authored-by: Tiago Trevisan Jost <tiago.trevisanjost@amd.com>
2024-02-22 21:16:33 +01:00
Boian Petkantchin
4f7ab789bf
[mlir][mesh] add support in spmdization for incomplete sharding annotations (#82442)
Don't require that `mesh.shard` operations come in pairs. If there is
only a single `mesh.shard` operation we assume that the producer result
and consumer operand have the same sharding.
2024-02-22 11:06:14 -08:00
Matthias Springer
55558cd05c
[mlir][Transforms][NFC] Turn block type conversion into IRRewrite (#81756)
This commit is a refactoring of the dialect conversion. The dialect
conversion maintains a list of "IR rewrites" that can be committed (upon
success) or rolled back (upon failure).

Until now, the signature conversion of a block was only a "partial" IR
rewrite. Rollbacks were triggered via
`BlockTypeConversionRewrite::rollback`, but there was no
`BlockTypeConversionRewrite::commit` equivalent.

Overview of changes:
* Remove `ArgConverter`, an internal helper class that kept track of all
block type conversions. There is now a separate
`BlockTypeConversionRewrite` for each block type conversion.
* No more special handling for block type conversions. They are now
normal "IR rewrites", just like "block creation" or "block movement". In
particular, trigger "commits" of block type conversion via
`BlockTypeConversionRewrite::commit`.
* Remove `ArgConverter::notifyOpRemoved`. This function was used to
inform the `ArgConverter` that an operation was erased, to prevent a
double-free of operations in certain situations. It would be unpractical
to add a `notifyOpRemoved` API to `IRRewrite`. Instead, erasing
ops/block should go through a new `SingleEraseRewriter` (that is owned
by the `ConversionPatternRewriterImpl`) if there is chance of
double-free. This rewriter ignores `eraseOp`/`eraseBlock` if the
op/block was already freed.
2024-02-22 10:22:27 +01:00