Commit Graph

409 Commits

Author SHA1 Message Date
Sirui Mu
93da6423af [mlir][LLVM] Add builders for llvm.intr.assume (#113317)
This patch adds several new builders for llvm.intr.assume that build the
operation with additional operand bundles.
2024-10-27 11:52:00 +08:00
Sirui Mu
1dfb104eac [mlir][LLVMIR] Add operand bundle support for llvm.intr.assume (#112143)
This patch adds operand bundle support for `llvm.intr.assume`.

This patch actually contains two parts:

- `llvm.intr.assume` now accepts operand bundle related attributes and
operands. `llvm.intr.assume` does not take constraint on the operand
bundles, but obviously only a few set of operand bundles are meaningful.
I plan to add some of those (e.g. `aligned` and `separate_storage` are
what interest me but other people may be interested in other operand
bundles as well) in future patches.

- The definitions of `llvm.call`, `llvm.invoke`, and
`llvm.call_intrinsic` actually define `op_bundle_tags` as an operation
property. It turns out this approach would introduce some unnecessary
burden if applied equally to the intrinsic operations because properties
are not available through `Operation *` but we have to operate on
`Operation *` during the import/export of intrinsics, so this PR changes
it from a property to an array attribute.

This patch relands commit d8fadad07c.
2024-10-16 20:49:02 +08:00
Sirui Mu
484c02780b Revert "[mlir][LLVMIR] Add operand bundle support for llvm.intr.assume (#112143)"
This reverts commit d8fadad07c.

The commit breaks the following CI builds:
- ppc64le-mlir-rhel-clang: https://lab.llvm.org/buildbot/#/builders/129/builds/7685
- ppc64le-flang-rhel-clang: https://lab.llvm.org/buildbot/#/builders/157/builds/10338
2024-10-16 14:15:31 +08:00
Sirui Mu
d8fadad07c [mlir][LLVMIR] Add operand bundle support for llvm.intr.assume (#112143)
This patch adds operand bundle support for `llvm.intr.assume`.

This patch actually contains two parts:

- `llvm.intr.assume` now accepts operand bundle related attributes and
operands. `llvm.intr.assume` does not take constraint on the operand
bundles, but obviously only a few set of operand bundles are meaningful.
I plan to add some of those (e.g. `aligned` and `separate_storage` are
what interest me but other people may be interested in other operand
bundles as well) in future patches.

- The definitions of `llvm.call`, `llvm.invoke`, and
`llvm.call_intrinsic` actually define `op_bundle_tags` as an operation
property. It turns out this approach would introduce some unnecessary
burden if applied equally to the intrinsic operations because properties
are not available through `Operation *` but we have to operate on
`Operation *` during the import/export of intrinsics, so this PR changes
it from a property to an array attribute.
2024-10-16 12:51:50 +08:00
Nikita Popov
e692af8596 [MLIR] Update APInt construction to correctly set isSigned/implicitTrunc (#110466)
This fixes all the places in MLIR that hit the new assertion added in
#106524, in preparation for enabling it by default. That is, cases where
the value passed to the APInt constructor is not an N-bit
signed/unsigned integer, where N is the bit width and signedness is
determined by the isSigned flag.

The fixes either set the correct value for isSigned, or set the
implicitTrunc flag to retain the old behavior. I've left TODOs for the
latter case in some places, where I think that it may be worthwhile to
stop doing implicit truncation in the future.

Note that the assertion is currently still disabled by default, so this
patch is mostly NFC.

This is just the MLIR changes split off from
https://github.com/llvm/llvm-project/pull/80309.
2024-10-14 15:01:05 +02:00
Abid Qadeer
cd12ffb622 [mlir][debug] Allow multiple DIGlobalVariableExpression on globals. (#111981)
Currently, we allow only one DIGlobalVariableExpressionAttr per global.
It is especially evident in import where we pick the first from the list
and ignore the rest. In contrast, LLVM allows multiple
DIGlobalVariableExpression to be attached to the global. They are needed
for correct working of things like DICommonBlock. This PR removes this
restriction in mlir. Changes are mostly mechanical. One thing on which I
went a bit back and forth was the representation inside GlobalOp. I
would be happy to change if there are better ways to do this.

---------

Co-authored-by: Tobias Gysi <tobias.gysi@nextsilicon.com>
2024-10-13 23:36:00 +01:00
Abid Qadeer
36c34ec967 [mlir][debug] Support DICommonBlock. (#111706)
A COMMON block is a named area of memory that holds a collection of
variables. Fortran subprograms may map the COMMON block memory area to a
list of variables. A common block is represented in LLVM debug by
DICommonBlock.

This PR adds support for this in MLIR. The changes are mostly mechanical
apart from small change to access the DICompileUnit when the scope of
the variable is DICommonBlock.

---------

Co-authored-by: Tobias Gysi <tobias.gysi@nextsilicon.com>
2024-10-10 18:07:06 +01:00
Finlay
741ad3ab8e [mlir][llvmir] Added extra builders for CallInstrinsicOp (#111664)
Extra builders for CallIntrinsicOp.
This is inspired by the comment from @antiagainst from
[here](https://github.com/llvm/llvm-project/pull/108933#issuecomment-2392751569).
2024-10-10 08:58:37 +01:00
Tobias Gysi
8e2ccdc4de [MLIR][LLVM] Use ViewLikeOpInterface (#111663)
This commit adds the ViewLikeOpInterface to the GEP and AddrSpaceCast
operations. This allows us to simplify the inliner interface. At the
same time, the change also makes the inliner interface more extensible
for downstream users that have custom view-like operations.
2024-10-09 14:37:01 +02:00
Ilya V
1b4b0c4c45 Allow fixed vector operand for LLVM_AtomicRMWOp (#110553)
This PR fixes `LLVM_AtomicRMWOp` allowed semantics and verifier logic to
enable building of `LLVM_AtomicRMWOp` with fixed vectors of compatible
fp values
as operands for fp rmw operation.

See also: https://llvm.org/docs/LangRef.html#id231

Signed-off-by: Ilya Veselov <iveselov.nn@gmail.com>
2024-10-03 18:15:29 +01:00
Sirui Mu
fde3c16ac9 [mlir][LLVM] Add operand bundle support (#108933)
This PR adds LLVM [operand
bundle](https://llvm.org/docs/LangRef.html#operand-bundles) support to
MLIR LLVM dialect. It affects these 3 operations related to making
function calls: `llvm.call`, `llvm.invoke`, and `llvm.call_intrinsic`.

This PR adds two new parameters to each of the 3 operations. The first
parameter is a variadic operand `op_bundle_operands` that contains the
SSA values for operand bundles. The second parameter is a property
`op_bundle_tags` which holds an array of strings that represent the tags
of each operand bundle.
2024-09-26 07:59:37 +02:00
JOE1994
884221eddb [mlir] Tidy uses of llvm::raw_stream_ostream (NFC)
As specified in the docs,
1) raw_string_ostream is always unbuffered and
2) the underlying buffer may be used directly

( 65b13610a5 for further reference )

* Don't call raw_string_ostream::flush(), which is essentially a no-op.
* Avoid unneeded calls to raw_string_ostream::str(), to avoid excess indirection.
2024-09-16 23:23:25 -04:00
Johannes de Fine Licht
6ab5829ab7 [MLIR][LLVM][NFC] Remove dead interface and add namespace qualifiers (#107573)
The `GetResultPtrElementType` interface is dead now that MLIR has fully
moved to opaque pointers, and can be removed.

Add namespace qualifiers to all argument types and return types of
interface methods for when they're used outside of LLVM dialect.
2024-09-06 15:56:02 +02:00
Tobias Gysi
751975530e Reapply "[MLIR][LLVM] Make DISubprogramAttr cyclic" (#106571) with fixes (#106947)
This reverts commit fa93be4, restoring
commit d884b77, with fixes that ensure the CAPI declarations are
exported properly.

This commit implements LLVM_DIRecursiveTypeAttrInterface for the
DISubprogramAttr to ensure cyclic subprograms can be imported properly.
In the process multiple shortcuts around the recently introduced
DIImportedEntityAttr can be removed.
2024-09-02 12:26:15 +02:00
Tobias Gysi
fa93be4b1c Revert "[MLIR][LLVM] Make DISubprogramAttr cyclic" (#106827)
Reverts llvm/llvm-project#106571

This commit breaks the following build bot:
https://lab.llvm.org/buildbot/#/builders/138/builds/2992
It looks like there is a missing dependency in this particular setup.
2024-08-31 07:51:53 +02:00
Tobias Gysi
d884b77c66 [MLIR][LLVM] Make DISubprogramAttr cyclic (#106571)
This commit implements LLVM_DIRecursiveTypeAttrInterface for the
DISubprogramAttr to ensure cyclic subprograms can be imported properly.
In the process multiple shortcuts around the recently introduced
DIImportedEntityAttr can be removed.
2024-08-31 07:23:24 +02:00
Sirui Mu
318b0678e3 [mlir][LLVM] Add support for constant struct with multiple fields (#102752)
Currently `mlir.llvm.constant` of structure types restricts that the
structure type effectively represents a complex type -- it must have
exactly two fields of the same type and the field type must be either an
integer type or a float type.

This PR relaxes this restriction and it allows the structure type to
have an arbitrary number of fields.
2024-08-22 15:32:55 +02:00
Christian Ulmann
4c2f90f362 [MLIR][LLVM] Turn the inliner interface into a promised interface (#103927)
This commit changes the LLVM dialect's inliner interface to no longer be
registered at dialect initialization. Instead, it is now a promised
interface, that needs to be registered explicitly. This change is
desired to avoid pulling in a lot of dependencies into the
`MLIRLLVMDialect` library, especially considering future patches that
plan to extend it further with strong IR analysis.
2024-08-14 17:28:54 +02:00
Matthias Springer
b8bf14eecf [mlir][LLVMIR] Check number of elements in mlir.constant verifier (#102906)
Check that the number of elements in the result type and the attribute
of an `llvm.mlir.constant` op matches. Also fix a broken test where that
was not the case.
2024-08-13 10:39:49 +02:00
James Y Knight
dfeb3991fb Remove the x86_mmx IR type. (#98505)
It is now translated to `<1 x i64>`, which allows the removal of a bunch
of special casing.

This _incompatibly_ changes the ABI of any LLVM IR function with
`x86_mmx` arguments or returns: instead of passing in mmx registers,
they will now be passed via integer registers. However, the real-world
incompatibility caused by this is expected to be minimal, because Clang
never uses the x86_mmx type -- it lowers `__m64` to either `<1 x i64>`
or `double`, depending on ABI.

This change does _not_ eliminate the SelectionDAG `MVT::x86mmx` type.
That type simply no longer corresponds to an IR type, and is used only
by MMX intrinsics and inline-asm operands.

Because SelectionDAGBuilder only knows how to generate the
operands/results of intrinsics based on the IR type, it thus now
generates the intrinsics with the type MVT::v1i64, instead of
MVT::x86mmx. We need to fix this before the DAG LegalizeTypes, and thus
have the X86 backend fix them up in DAGCombine. (This may be a
short-lived hack, if all the MMX intrinsics can be removed in upcoming
changes.)

Works towards issue #98272.
2024-07-25 09:19:22 -04:00
Finlay
2eea9d6a2d [mlir] Rename memory attribute to memory_effects in llvmir dialect (#100108)
This commit renames the memory attribute on operations to "memory_effects" to be in line with the naming LLVM IR is using.
2024-07-23 14:17:05 +02:00
Finlay
fde27bd221 [mlir] Added new attributes to the llvm.call op in llvmir target (#99663)
The new attributes are:
 * convergent
 * no_unwind
 * will_return
 * memory effects
2024-07-23 12:44:13 +02:00
Tobias Gysi
5da4310082 [MLIR][LLVM] Always print variadic callee type (#99293)
This commit updates the LLVM dialect CallOp and InvokeOp to always print
the variadic callee type (previously callee type) if present. An
additional verifier checks that only variadic calls have a non-null
variadic callee type, and the builders are adapted accordingly to set
the variadic callee type for variadic calls only. Finally, the CallOp
and InvokeOp verifiers are strengthened to check that the variadic
callee type matches the call argument and result types.

The motivation of this change is that CallOp and InvokeOp don't have
hidden state that is not pretty printed, but used during the export to
LLVM IR. Previously, it could happen that a call looked correct in MLIR,
but the return type changed after exporting to LLVM IR (since it has
been taken from the hidden callee type attribute). After landing this
change, this is not possible anymore since the variadic callee type is
always printed if present.
2024-07-23 08:21:46 +02:00
Steffi Stumpos
4a01079931 Expose Tail Kind Call to MLIR (#98080)
I would like to mark a call op in LLVM dialect as Musttail. The calling
convention attribute only exposes Tail, not Musttail. I noticed that the
CallInst of LLVM has an additional field to specify the flavor of tail
call kind. I bubbled this up to the LLVM dialect by adding another
attribute that maps to LLVM::CallInst::TailCallKind.
2024-07-09 14:04:33 -07:00
Cullen Rhodes
1e7d6d3455 [mlir][vector] Propagate scalability to gather/scatter ptrs vector (#97584)
In convert-vector-to-llvm the first operand (vector of pointers holding
all memory addresses to read) to the masked.gather (and scatter)
intrinsic has a fixed vector type.

This may result in intrinsics where the scalable flag has been dropped:
```
  %0 = llvm.intr.masked.gather %1, %2, %3 {alignment = 4 : i32}
    : (!llvm.vec<4 x ptr>, vector<[4]xi1>, vector<[4]xi32>) -> vector<[4]xi32>
```
Fortunately the operand is overloaded on the result type so we end up
with the correct IR when lowering to LLVM, but this is still incorrect.
This patch fixes it by propagating scalability.
2024-07-09 09:06:25 +01:00
donald chen
2c1ae801e1 [mlir][side effect] refactor(*): Include more precise side effects (#94213)
This patch adds more precise side effects to the current ops with memory
effects, allowing us to determine which OpOperand/OpResult/BlockArgument
the
operation reads or writes, rather than just recording the reading and
writing
of values. This allows for convenient use of precise side effects to
achieve
analysis and optimization.

Related discussions:
https://discourse.llvm.org/t/rfc-add-operandindex-to-sideeffect-instance/79243
2024-06-19 22:10:34 +08:00
Johannes de Fine Licht
c012e487b7 [MLIR][LLVM] Promote noinline/alwaysinline/optnone out of passthrough (#95110)
The `noinline`, `alwaysinline`, and `optnone` function attributes are
already being used in MLIR code for the LLVM inlining interface and in
some SPIR-V lowering, despite residing in the passthrough dictionary,
which is intended as exactly that -- a pass through MLIR -- and not to
model any actual semantics being handled in MLIR itself.

Promote the `noinline`, `alwaysinline`, and `optnone` attributes out of
the passthrough dictionary on `llvm.func` into first class unit
attributes, updating the import and export accordingly.

Add a verifier to `llvm.func` that checks that these attributes are not
set in an incompatible way according to the LLVM specification.

Update the LLVM dialect inlining interface to use the first class
attributes to check whether inlining is possible.
2024-06-12 08:29:02 +02:00
Abid Qadeer
4f320e6aa2 [MLIR] Translate DIStringType. (#94480)
This PR handle translation of DIStringType. Mostly mechanical changes to
translate DIStringType to/from DIStringTypeAttr. The 'stringLength'
field is 'DIVariable' in DIStringType. As there was no `DIVariableAttr`
previously, it has been added to ease the translation.

---------

Co-authored-by: Tobias Gysi <tobias.gysi@nextsilicon.com>
2024-06-07 09:59:47 +01:00
Guy David
4bce270157 [mlir][llvm] Implement ConstantLike for ZeroOp, UndefOp, PoisonOp (#93690)
These act as constants and should be propagated whenever possible. It is
safe to do so for mlir.undef and mlir.poison because they remain "dirty"
through out their lifetime and can be duplicated, merged, etc. per the
LangRef.

Signed-off-by: Guy David <guy.david@nextsilicon.com>
2024-05-30 08:21:08 +02:00
Christian Ulmann
e6216906f5 [MLIR][LLVM] Improve atomic verifier to properly support larger types (#92120)
This commit extends the verifier for atomics to properly verify larger
types. Beforehand, the verifier strictly rejected larger integer types,
while it now consults the data layout to determine if their bitsize is a
power of two. This behavior reflects what LLVM's verifier is checking
for.
2024-05-15 08:31:09 +02:00
Thomas Raoux
5526c8a742 [MLIR] Model llvm.inline_asm side_effects (#91507)
Allow more cleanups on inline_asm ops modeling side effects based on the
side_effect attributed.
2024-05-08 12:35:15 -07:00
Johannes de Fine Licht
92ca6fcb87 [MLIR][LLVM] Have LLVM::AddressOfOp implement ConstantLike (#90481)
For all means and purposes llvm.mlir.addressof acts like a constant, and
should be treated as such by passes. In particular, the operation should
be propagated rather than passed whenever possible.
2024-04-30 10:00:28 +02:00
Christian Ulmann
4513050f52 [MLIR] Harmonize the behavior of the folding API functions (#88508)
This commit changes `OpBuilder::tryFold` to behave more similarly to
`Operation::fold`. Concretely, this ensures that even an in-place fold
returns `success`.
This is necessary to fix a bug in the dialect conversion that occurred
when an in-place folding made an operation legal. The dialect conversion
infrastructure did not check if the result of an in-place folding
legalized the operation and just went ahead and tried to apply pattern
anyways.

The added test contains a simplified version of a breakage we observed
downstream.
2024-04-23 08:05:55 +02:00
Jeff Niu
e553ac4d81 [mlir][llvm] Port overflowFlags to a native operation property (RELAND) (#89410)
This PR changes the LLVM dialect's IntegerOverflowFlags to be stored on
operations as native properties.

Reland to fix flang
2024-04-19 09:23:00 -07:00
Christian Sigg
a5757c5b65 Switch member calls to isa/dyn_cast/cast/... to free function calls. (#89356)
This change cleans up call sites. Next step is to mark the member
functions deprecated.

See https://mlir.llvm.org/deprecation and
https://discourse.llvm.org/t/preferred-casting-style-going-forward.
2024-04-19 15:58:27 +02:00
Valentin Clement (バレンタイン クレメン)
13beabe5e9 Revert "[mlir][llvm] Port overflowFlags to a native operation property" (#89344)
Reverts llvm/llvm-project#89312 as it breaks all flang buildbots
2024-04-18 22:15:42 -07:00
Jeff Niu
0c41eea474 [mlir][llvm] Port overflowFlags to a native operation property (#89312)
This PR changes the LLVM dialect's IntegerOverflowFlags to be stored on
operations as native properties.
2024-04-18 15:35:39 -07:00
Christian Ulmann
ef8322f41d [MLIR][LLVM] Improve bit- and addrspacecast folders (#87745)
This commit extends the folders of chainable casts (bitcast and
addrspacecast) to ensure that they fold a chain of the same casts into a
single cast.

Additionally cleans up the canonicalization test file, as this used some
outdated constructs.
2024-04-05 09:14:13 +02:00
Jakub Kuderski
971b852546 [mlir][NFC] Simplify type checks with isa predicates (#87183)
For more context on isa predicates, see:
https://github.com/llvm/llvm-project/pull/83753.
2024-04-01 11:40:09 -04: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
Mehdi Amini
acf2f24ac3 Apply clang-tidy fixes for llvm-else-after-return in LLVMDialect.cpp (NFC) 2024-01-22 17:34:56 -08:00
Krzysztof Drewniak
2aff7f3919 [mlir][LLVM] Add !invariant.load metadata support to llvm.load (#76754)
Add support for !invariant.load metadata (by way of a unit attribute) to
the MLIR representation of llvm.load.
2024-01-04 09:33:09 -06:00
gitoleg
8cf6bcf5a3 [mlir][llvm] Add assert in CallOp builder (#76240)
This commit adds an assert in one of the CallOp builders to ensure it is not use to create an indirect call. Otherwise, the callee type would include the callee pointer type which is handed in as first argument.
2023-12-27 17:08:35 +01:00
Kazu Hirata
88d319a29f [mlir] Use StringRef::{starts,ends}_with (NFC)
This patch replaces uses of StringRef::{starts,ends}with with
StringRef::{starts,ends}_with for consistency with
std::{string,string_view}::{starts,ends}_with in C++20.

I'm planning to deprecate and eventually remove
StringRef::{starts,ends}with.
2023-12-13 22:58:30 -08:00
Tom Eccles
e9e1c411b6 [mlir][LLVM] Add nsw and nuw flags (#74508)
The implementation of these are modeled after the existing fastmath
flags for floating point arithmetic.
2023-12-07 10:35:00 +00:00
Billy Zhu
12e5148f9c [MLIR][LLVM] Fix CallOp asm parser for attr-dict (#74372)
Currently the parser & printer of `CallOp` do not match when both
varargs and attr-dict are present (round tripping is broken). This fixes
the parser so that it conforms to the written asm format in the
comments.
2023-12-05 21:18:52 +01:00
Rik Huijzer
13da9a58c5 [mlir][llvm] Fix verifier for const int and dense (#74340)
Continuation of https://github.com/llvm/llvm-project/pull/74247 to fix
https://github.com/llvm/llvm-project/issues/56962. Fixes verifier for
(Integer Attr):
```mlir
llvm.mlir.constant(1 : index) : f32
```
and (Dense Attr):
```mlir
llvm.mlir.constant(dense<100.0> : vector<1xf64>) : f32
```

## Integer Attr

The addition that this PR makes to `LLVM::ConstantOp::verify` is meant
to be exactly verifying the code in
`mlir::LLVM::detail::getLLVMConstant`:


9f78edbd20/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (L350-L353)

One failure mode is when the `type` (`llvm.mlir.constant(<value>) :
<type>`) is not an `Integer`, because then the `cast` in
`getIntegerBitWidth` will crash:


dca432cb7b/llvm/include/llvm/IR/DerivedTypes.h (L97-L99)

So that's now caught in the verifier.

Apart from that, I don't see anything we could check for. `sextOrTrunc`
means "Sign extend or truncate to width" and that one is quite
permissive. For example, the following doesn't have to be caught in the
verifier as it doesn't crash during `mlir-translate -mlir-to-llvmir`:

```mlir
llvm.func @main() -> f32 {
  %cst = llvm.mlir.constant(100 : i64) : f32
  llvm.return %cst : f32
}
```

## Dense Attr

Crash if not either a MLIR Vector type or one of these:


9f78edbd20/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (L375-L391)
2023-12-05 12:31:49 +01:00
Justin Wilson
6da578cec1 [mlir] Add support for DIGlobalVariable and DIGlobalVariableExpression (#73367)
This PR introduces DIGlobalVariableAttr and
DIGlobalVariableExpressionAttr so that ModuleTranslation can emit the
required metadata needed for debug information about global variable.
The translator implementation for debug metadata needed to be refactored
in order to allow translation of nodes based on MDNode
(DIGlobalVariableExpressionAttr and DIExpression) in addition to
DINode-based nodes.

A DIGlobalVariableExpressionAttr can now be passed to the GlobalOp
operation directly and ModuleTranslation will create the respective
DIGlobalVariable and DIGlobalVariableExpression nodes. The compile unit
that DIGlobalVariable is expected to be configured with will be updated
with the created DIGlobalVariableExpression.
2023-12-04 15:52:02 +01:00
Rik Huijzer
67f9cd4670 [mlir][llvm] Fix verifier for const float (#74247)
Fixes one of the cases of
https://github.com/llvm/llvm-project/issues/56962.

This PR basically moves some code from
`mlir::LLVM::detail::getLLVMConstant`
([source](9f78edbd20/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (L354-L371)))
over to the verifier of `LLVM::ConstantOp`. For now, I focused just on
the case where the attribute is a float and ignored the integer case of
https://github.com/llvm/llvm-project/issues/56962. Note that without
this patch, both added tests will crash inside `getLLVMConstant` during
`mlir-translate -mlir-to-llvmir`.
2023-12-04 08:06:02 +01:00
David Truby
a72e034f13 [mlir] Add llvm.linker.options operation to the LLVM IR Dialect (#71720)
This patch adds a `llvm.linker.options` operation taking a list of
strings to pass to the linker when the resulting object file is linked.
This is particularly useful on Windows to specify the CRT version to use
for this object file.
2023-11-13 14:13:05 +00:00