Commit Graph

3547 Commits

Author SHA1 Message Date
Stephan Herhut fdcecefe30 Add lowering for loop.parallel to cfg.
Summary:
This also removes the explicit pattern for loop.terminator to ensure
that the terminator is only erased if the parent op is rewritten.

Reductions are not yet supported.

Reviewers: nicolasvasilache

Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73348
2020-01-28 11:55:51 +01:00
Alex Zinenko 8ed47b7430 [mlir] NFC: use ValueRange in AffineToStandard conversion
ValueRange is a more flexible way of passing around ranges of Values
that avoids Value vector materialization in affine expression expansion.
2020-01-28 11:54:52 +01:00
Julian Gross 88d6f18225 [mlir] fixed invalid LLVM intrinsics in LLVMOPs.td and llvmir-intrinsics.mlir.
Summary:
The intrinsic operation added multiple type annotations to the llvm intrinsic operations, but only one is needed.
The related tests in llvmir-intrinsics.mlir checked the wrong number and are adjusted as well.

Reviewers: nicolasvasilache, ftynse

Reviewed By: ftynse

Subscribers: merge_guards_bot, ftynse, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73470
2020-01-28 11:01:22 +01:00
Julian Gross 664d2f5bad Add tanh lowering from Standard dialect to NVVM and ROCDL.
Summary:
The tanh lowering from Standard dialect to NVVM and ROCDL was not working.
The conversion pattern are inserted in the lowering files.
The test cases for the lowerings were added in the test files.

Reviewers: nicolasvasilache, ftynse, herhut

Reviewed By: ftynse, herhut

Subscribers: merge_guards_bot, ftynse, jholewinski, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, csigg, arpith-jacob, mgester, lucyrfox, herhut, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73471
2020-01-28 11:01:10 +01:00
Alex Zinenko 6895a1c37e [mlir] NFC: use doxygen-style comments in AffineToStandard.cpp 2020-01-28 10:22:30 +01:00
River Riddle 57540c96be [mlir] Replace toy::DeadFunctionEliminationPass with symbolDCEPass.
Summary:
The dead function elimination pass in toy was a temporary stopgap until we had proper dead function elimination support in MLIR. Now that this functionality is available, this pass is no longer necessary.

Differential Revision: https://reviews.llvm.org/D72483
2020-01-27 23:48:06 -08:00
River Riddle b276dec5b6 [mlir] Add a DCE pass for dead symbols.
Summary: This pass deletes all symbols that are found to be unreachable. This is done by computing the set of operations that are known to be live, propagating that liveness to other symbols, and then deleting all symbols that are not within this live set.

Differential Revision: https://reviews.llvm.org/D72482
2020-01-27 23:29:30 -08:00
River Riddle ab9e5598cd [mlir] Refactor the implementation of Symbol use lists.
Summary: This revision refactors the implementation of the symbol use-list functionality to be a bit cleaner, as well as easier to reason about. Aside from code cleanup, this revision updates the user contract to never recurse into operations if they define a symbol table. The current functionality, which does recurse, makes it difficult to examine the uses held by a symbol table itself. Moving forward users may provide a specific region to examine for uses instead.

Differential Revision: https://reviews.llvm.org/D73427
2020-01-27 23:01:46 -08:00
River Riddle aff4ed7326 [mlir][NFC] Update Operation::getResultTypes to use ArrayRef<Type> instead of iterator_range.
Summary: The new internal representation of operation results now allows for accessing the result types to be more efficient. Changing the API to ArrayRef is more efficient and removes the need to explicitly materialize vectors in several places.

Differential Revision: https://reviews.llvm.org/D73429
2020-01-27 19:57:48 -08:00
River Riddle ce674b131b [mlir] Add support for marking 'unknown' operations as dynamically legal.
Summary: This allows for providing a default "catchall" legality check that is not dependent on specific operations or dialects. For example, this can be useful to check legality based on the specific types of operation operands or results.

Differential Revision: https://reviews.llvm.org/D73379
2020-01-27 19:50:52 -08:00
Diego Caballero 6fb3d59746 [mlir] Remove 'valuesToRemoveIfDead' from PatternRewriter API
Summary:
Remove 'valuesToRemoveIfDead' from PatternRewriter API. The removal
functionality wasn't implemented and we decided [1] not to implement it in
favor of having more powerful DCE approaches.

[1] https://github.com/tensorflow/mlir/pull/212

Reviewers: rriddle, bondhugula

Reviewed By: rriddle

Subscribers: liufengdb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72545
2020-01-27 14:00:34 -08:00
Kern Handa 74df89f67f [NFC][mlir][linalg] Merge Utils/Intrinsics.h into EDSC/Intrinsics.h
Differential Revision: https://reviews.llvm.org/D73377
2020-01-27 22:32:11 +01:00
Alex Zinenko 51ba5b528a [mlir] add lowering from affine.min to std
Summary:
Affine minimum computation will be used in tiling transformation. The
implementation is mostly boilerplate as we already lower the minimum in the
upper bound of an affine loop.

Differential Revision: https://reviews.llvm.org/D73488
2020-01-27 22:30:52 +01:00
aartbik 459cf6e500 [mlir] [VectorOps] Lowering of vector.extract/insert_slices to LLVM IR
Summary: Uses progressive lowering to convert vector.extract_slices and vector_insert_slices to equivalent vector operations that can be subsequently lowered into LLVM.

Reviewers: nicolasvasilache, andydavis1, rriddle

Reviewed By: nicolasvasilache, rriddle

Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72808
2020-01-27 10:35:48 -08:00
Alex Zinenko 84c3f05c8e [mlir] Harden error propagation in LLVM import
Summary:
LLVM importer to MLIR was implemented mostly as a prototype. As such, it did
not deal handle errors in a consistent way, reporting them out stderr in some
cases and continuing the execution in the error state until eventually
crashing. This is not desirable for a user-facing tool. Make sure errors are
returned from functions, consistently checked at call sites and propagated
further. Functions returning nullable IR values return nullptr to denote the
error state. Other functions return LogicalResult. LLVM importer in
mlir-translate should no longer crash on unsupported inputs.

The errors are reported without association with the source file (and therefore
cannot be checked using -verify-diagnostics). Attaching them to the actual
input file is left for future work.

Differential Revision: https://reviews.llvm.org/D72839
2020-01-27 16:15:11 +01:00
Alex Zinenko 07328944ef [mlir] LLVM import: handle constant data and array/vector aggregates
Summary:
Implement the handling of llvm::ConstantDataSequential and
llvm::ConstantAggregate for (nested) array and vector types when imporitng LLVM
IR to MLIR. In all cases, the result is a DenseElementsAttr that can be used in
either a `llvm.mlir.global` or a `llvm.mlir.constant`. Nested aggregates are
unpacked recursively until an element or a constant data is found. Nested
arrays with innermost scalar type are represented as DenseElementsAttr of
tensor type. Nested arrays with innermost vector type are represented as
DenseElementsAttr with (multidimensional) vector type.

Constant aggregates of struct type are not yet supported as the LLVM dialect
does not have a well-defined way of modeling struct-type constants.

Differential Revision: https://reviews.llvm.org/D72834
2020-01-27 16:15:11 +01:00
Lei Zhang 29e411b3d6 [mlir] Expose getNearestSymbolTable as SymbolTable class method
This is a generally useful utility function for interacting with
symbol tables.

Differential Revision: https://reviews.llvm.org/D73433
2020-01-26 17:35:26 -05:00
Lei Zhang 8d6884a15e [mlir][spirv] Create builtin variable in nearest symbol table
This commit changes the logic of `getBuiltinVariableValue` to get
or create the builtin variable in the nearest symbol table. This
will allow us to use this function in other partial conversion
cases where we haven't created the spv.module yet.

Differential Revision: https://reviews.llvm.org/D73416
2020-01-26 11:00:49 -05:00
Lei Zhang 09f9deaff2 [mlir][spirv] NFC: simplify load/store builder call sites
This commit introduces default values for load/store builders to
simplify builder call sites.

Differential Revision: https://reviews.llvm.org/D73419
2020-01-26 10:45:42 -05:00
Lei Zhang 91d6655a29 [mlir][spirv] NFC: expose builtin func op conversion pattern
This commit exposes the func op conversion pattern via a new
`populateBuiltinFuncToSPIRVPatterns` function from the standard
to SPIR-V conversion passs. This is structurally better given
that func op belongs to the builtin dialect. More importantly,
this makes the pattern reusable to other dialect to SPIR-V
dialect conversion as other dialect can well adopt builtin
func op instead of having its own. Besides, it's very common
to use func ops as test wrappers in lit tests, so test passes
will need to handle func ops too.

Differential Revision: https://reviews.llvm.org/D73421
2020-01-26 10:42:06 -05:00
Lei Zhang 60d541e1b9 [mlir][spirv] Relax verification to allow flexible placement
Thus far certain SPIR-V ops have been required to be in spv.module.
While this provides strong verification to catch unexpected errors,
it's quite rigid and makes progressive lowering difficult. Sometimes
we would like to partially lower ops from other dialects, which may
involve creating ops like global variables that should be placed in
other module-like ops. So this commit relaxes the requirement of
such SPIR-V ops' scope to module-like ops. Similarly for function-
like ops.

Differential Revision: https://reviews.llvm.org/D73415
2020-01-26 10:39:45 -05:00
Lei Zhang ae21e37eb4 [mlir][spirv] Add spv.GroupNonUniformElect and spv.GroupNonUniformIAdd
Differential Revision: https://reviews.llvm.org/D73349
2020-01-26 10:20:40 -05:00
Mehdi Amini 308571074c Mass update the MLIR license header to mention "Part of the LLVM project"
This is an artifact from merging MLIR into LLVM, the file headers are
now aligned with the rest of the project.
2020-01-26 03:58:30 +00:00
Jacques Pienaar e47b561398 [mlir] Revert MSVC specific part of whole_archive_link
Revert the MSVC specific parts in whole_archive_link to previous form to
potentially address https://bugs.llvm.org/show_bug.cgi?id=44660.
2020-01-25 09:56:04 -08:00
Jacques Pienaar e298e21650 [mlir] Bootstrap doxygen config
Add basic doxygen config following clang and llvm example with minimal
changes.
2020-01-25 09:31:59 -08:00
aartbik 303fddeeab [mlir] [VectorOps] Rewriting of vector.extract/insert_slices to other vector ops
Summary:
Rewrites the extract/insert_slices operation in terms of
strided_slice/insert_strided_slice ops with intermediate
tuple uses (that should get optimimized away with typical
usage). This is done in a separate "pass" to enable testing
this particular rewriting in isolation.

Reviewers: nicolasvasilache, andydavis1, ftynse

Reviewed By: nicolasvasilache

Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73295
2020-01-24 16:24:45 -08:00
Alex Zinenko b901335193 [mlir] Use all_of instead of a manual loop in IntrinsicGen. NFC
This was suggested in post-commit review of D72926.
2020-01-24 11:29:35 +01:00
aartbik aabc3c59e1 [mlir] [VectorOps] fixed minor typos in vector ops doc
Summary:
Rationale:
Some examples were using "offsets : [0, 2]" syntax which
should use a "=" instead. The same examples were referring
to the integer attribute array as k-dimensional, which is
a bit confusing (it is 1-dimensional, with k elements).
Changed to "k-sized".

Reviewers: nicolasvasilache, andydavis1, ftynse

Reviewed By: nicolasvasilache

Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73293
2020-01-23 15:33:45 -08:00
aartbik ed8222b2ca [mlir] [VectorOps] Implement vector tuple get folding
Summary: Rewrites get-i tup<a1,...,an> into ai

Reviewers: nicolasvasilache, rriddle, andydavis1

Reviewed By: nicolasvasilache, rriddle, andydavis1

Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73213
2020-01-23 14:15:27 -08:00
Marcello Maggioni be9f09c768 [mlir] Add option to use custom base class for dialect in LLVMIRIntrinsicGen.
Summary:
LLVMIRIntrinsicGen is using LLVM_Op as the base class for intrinsics.
This works for LLVM intrinsics in the LLVM Dialect, but when we are
trying to convert custom intrinsics that originate from a custom
LLVM dialect (like NVVM or ROCDL) these usually have a different
"cppNamespace" that needs to be applied to these dialect.

These dialect specific characteristics (like "cppNamespace")
are typically organized by creating a custom op (like NVVM_Op or
ROCDL_Op) that passes the correct dialect to the LLVM_OpBase class.

It seems natural to allow LLVMIRIntrinsicGen to take that into
consideration when generating the conversion code from one of these
dialect to a set of target specific intrinsics.

Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse

Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73233
2020-01-23 11:23:25 -08:00
Ahmed Taei 8d1ed2940d [mlir] Fix vectorize transform crashing on none-op operand 2020-01-23 09:57:16 -08:00
Alex Zinenko c8695ba9cd Revert "[mlir] Add baseAttr to TypedArrayAttrBase."
This reverts commit eec36909c1.

This modeling is incorrect. baseAttr is intended for attribute
decorators that are not backed by C++ attribute classes. It essentially
says DerivedAttr isa BaseAttr, which is wrong for ArrayAttr classes.
If one needs to store the element type, it should be stored as a
separate filed in the tablegen class.
2020-01-23 14:47:11 +01:00
Benjamin Kramer 90c01357b8 [mlir] Shrink-wrap anonymous namespaces around the classes it's supposed to enclose. NFC.
The coding standards prefer smaller anonymous namespaces with free
functions just being static and in the global namespace.
2020-01-23 11:47:20 +01:00
Nicolas Vasilache 5bb8d28e61 [mlir][Linalg] Add tensor support to Linalg EDSC Builders
Summary:
This diff extends the Linalg EDSC builders so we can easily create mixed
tensor/buffer linalg.generic ops. This is expected to be useful for
HLO -> Linalg lowering.

The StructuredIndexed struct is made to derive from ValueHandle and can
now capture a type + indexing expressions. This is used to represent return
tensors.

Pointwise unary and binary builders are extended to allow both output buffers
and return tensors. This has implications on the number of region arguments.

Reviewers: ftynse, hanchung, asaadaldien

Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73149
2020-01-22 16:57:27 -05:00
Abdurrahman Akkas eec36909c1 [mlir] Add baseAttr to TypedArrayAttrBase.
Element type is useful in code generators but it is lost after construction.

Differential Revision: https://reviews.llvm.org/D72888
2020-01-22 19:35:41 +00:00
Mehdi Amini 5114d55dde [Flang] add some cmake code to allow for out-of-tree building of MLIR and LLVM
Differential Revision: https://reviews.llvm.org/D72418
2020-01-22 17:43:15 +00:00
Marcello Maggioni 04a151710e [mlir] Swap use of to_vector() with lookupValues() in LLVMIRIntrinsicGen
Summary:
llvm::to_vector() accepts a Range value and not the pair of arguments
we are currently passing. Also we probably want the lowered LLVM
values in the vector, while operand_begin()/operand_end() on MLIR ops
returns MLIR types. lookupValues() seems the correct way to collect
such values.

Reviewers: rriddle, andydavis1, antiagainst, nicolasvasilache, ftynse

Subscribers: jdoerfert, mehdi_amini, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D73137
2020-01-22 07:56:24 -08:00
Denis Khalikov 4460cb5bcd [mlir][spirv] Add lowering for composite std.constant.
Add lowering for constant operation with ranked tensor type to
spv.constant with spv.array type.

Differential Revision: https://reviews.llvm.org/D73022
2020-01-22 08:25:00 -05:00
Jacques Pienaar 178562fb35 [mlir] Enable specifying verify on OpInterface
Summary:
Add method in ODS to specify verification for operations implementing a
OpInterface. Use this with infer type op interface to verify that the
inferred type matches the return type and remove special case in
TestPatterns.

This could also have been achieved by using OpInterfaceMethod but verify
seems pretty common and it is not an arbitrary method that just happened
to be named verifyTrait, so having it be defined in special way seems
appropriate/better documenting.

Differential Revision: https://reviews.llvm.org/D73122
2020-01-22 04:43:22 -08:00
Alex Zinenko 7984b47401 [mlir][orc] unbreak MLIR ExecutionEngine after ORC changes
Changes to ORC in ce2207abaf changed the
APIs in IRCompileLayer, now requiring the custom compiler to be wrapped
in IRCompileLayer::IRCompiler. Even though MLIR relies on Orc
CompileUtils, the type is still visible in several places in the code.
Adapt those to the new API.
2020-01-22 10:16:20 +01:00
Nicolas Vasilache c0a26a35ee Revert "[mlir][Linalg] Add tensor support to Linalg EDSC Builders"
This reverts commit 89e19e8edd.

This committed a stale version of the diff https://reviews.llvm.org/D72863 .. I apologize, reverting.
2020-01-21 19:43:27 -05:00
Nicolas Vasilache 89e19e8edd [mlir][Linalg] Add tensor support to Linalg EDSC Builders
Summary:
This diff extends the Linalg EDSC builders so we can easily create mixed
tensor/buffer linalg.generic ops. This is expected to be useful for
HLO -> Linalg lowering.

The `StructuredIndexed` struct is made to derive from `ValueHandle` and can
now capture a type + indexing expressions. This is used to represent return
tensors.

Pointwise unary and binary builders are extended to allow both output buffers
and return tensors. This has implications on the number of region arguments.

Reviewers: ftynse, herhut, hanchung, asaadaldien, stellaraccident

Reviewed By: asaadaldien

Subscribers: merge_guards_bot, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72863
2020-01-21 19:37:54 -05:00
Marcello Maggioni cbf08d0f57 [mlir] Fix LLVM intrinsic convesion generator for overloadable types.
Summary:
If an intrinsic has overloadable types like llvm_anyint_ty or
llvm_anyfloat_ty then to getDeclaration() we need to pass a list
of the types that are "undefined" essentially concretizing them.

This patch add support for deriving such types from the MLIR op
that has been matched.

Reviewers: andydavis1, ftynse, nicolasvasilache, antiagainst

Subscribers: mehdi_amini, rriddle, jpienaar, burmako, shauheen, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72974
2020-01-21 11:52:30 -08:00
Lei Zhang f2dc179d68 [mlir][ods] Fix StringRef initialization in builders
For the generated builder taking in unwrapped attribute values,
if the argument is a string, we should avoid wrapping it in quotes;
otherwise we are always setting the string attribute to contain
the string argument's name. The quotes come from StrinAttr's
`constBuilderCall`, which is reasonable for string literals, but
not function arguments containing strings.

Differential Revision: https://reviews.llvm.org/D72977
2020-01-21 14:12:27 -05:00
Denis Khalikov 3023352a7d [mlir][spirv] Simplify scalar type size calculation.
Simplify scalar type size calculation and reject boolean memrefs.

Differential Revision: https://reviews.llvm.org/D72999
2020-01-21 12:15:37 -05:00
Tres Popp 9a52ea5cf9 Create a gpu.module operation for the GPU Dialect.
Summary:
This is based on the use of code constantly checking for an attribute on
a model and instead represents the distinct operaion with a different
op. Instead, this op can be used to provide better filtering.

Reverts "Revert "[mlir] Create a gpu.module operation for the GPU Dialect.""

This reverts commit ac446302ca4145cdc89f377c0c364c29ee303be5 after
fixing internal Google issues.

This additionally updates ROCDL lowering to use the new gpu.module.

Reviewers: herhut, mravishankar, antiagainst, nicolasvasilache

Subscribers: jholewinski, mgorny, mehdi_amini, jpienaar, burmako, shauheen, csigg, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, llvm-commits, mravishankar, rriddle, antiagainst, bkramer

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72921
2020-01-21 14:05:03 +01:00
Frank Laub fffea2842d [MLIR] LLVM Dialect: add llvm.cmpxchg and improve llvm.atomicrmw custom parser
Summary:
Add a `llvm.cmpxchg` op as a counterpart to LLVM IR's `cmpxchg` instruction.
Note that the `weak`, `volatile`, and `syncscope` attributes are not yet supported.

This will be useful for upcoming parallel versions of affine.for and generally
for reduction-like semantics (especially for reductions that can't make use
of `atomicrmw`, e.g. `fmax`).

Reviewers: ftynse, nicolasvasilache

Reviewed By: ftynse

Subscribers: merge_guards_bot, jfb, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, arpith-jacob, mgester, lucyrfox, liufengdb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72995
2020-01-21 01:09:42 -08:00
Mehdi Amini fdb9cc7dc5 Fix printer for llvm.addressof symbol name that need escaping
Differential Revision: https://reviews.llvm.org/D73065
2020-01-20 22:09:18 +00:00
Jacques Pienaar b70e4efb75 [mlir] Generalize broadcastable trait operands
Summary:
Generalize broadcastable trait to variadic operands. Update the
documentation that still talked about element type as part of
broadcastable trait (that bug was already fixed). Also rename
Broadcastable to ResultBroadcastableShape to be more explicit that the
trait affects the result shape (it is possible for op to allow
broadcastable operands but not have result shape that is broadcast
compatible with operands).

Doing some intermediate work to have getBroadcastedType take an optional
elementType as input and use that if specified, instead of the common
element type of type1 and type2 in this function.

Differential Revision: https://reviews.llvm.org/D72559
2020-01-20 13:02:14 -08:00
Alex Zinenko f63f5a228f [mlir] clarify LangRef wording around control flow in regions
It was unclear what "exiting a region" meant in the existing formulation.
Phrase it in terms of control flow transfer to the operation enclosing the
region.

Discussion: https://groups.google.com/a/tensorflow.org/d/msg/mlir/73d2O8gjTuA/xVj1KoCTBAAJ
2020-01-20 14:29:57 +01:00