Commit Graph

15165 Commits

Author SHA1 Message Date
Pengxuan Zheng 38612fbc89 Reland "[COFF, ARM64] Add __break intrinsic"
https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170

Reland after fixing the test failure. The failure was due to conflict with a
change (D122983) which was merged right before this patch.

Reviewed By: rnk, mstorsjo

Differential Revision: https://reviews.llvm.org/D124032
2022-04-20 13:01:30 -07:00
Pengxuan Zheng bff8356b19 Revert "[COFF, ARM64] Add __break intrinsic"
This reverts commit 8a9b4fb4aa.
2022-04-20 11:57:49 -07:00
Eli Friedman ecc8479a01 Look through calls to std::addressof to compute pointer alignment.
This is sort of a followup to D37310; that basically fixed the same
issue, but then the libstdc++ implementation of <atomic> changed. Re-fix
the the issue in essentially the same way: look through the addressof
operation to find the alignment of the underlying object.

Differential Revision: https://reviews.llvm.org/D123950
2022-04-20 11:30:11 -07:00
Pengxuan Zheng 8a9b4fb4aa [COFF, ARM64] Add __break intrinsic
https://docs.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170

Reviewed By: rnk, mstorsjo

Differential Revision: https://reviews.llvm.org/D124032
2022-04-20 11:20:26 -07:00
Fangrui Song a57d16bf80 [CodeGen] Fix -Wswitch after D116462 2022-04-19 17:33:15 -07:00
Fangrui Song 8b0e7f2293 [CodeGen] Fix -Wswitch after D116462 2022-04-19 17:28:54 -07:00
Paul Kirth bac6cd5bf8 [misexpect] Re-implement MisExpect Diagnostics
Reimplements MisExpect diagnostics from D66324 to reconstruct its
original checking methodology only using MD_prof branch_weights
metadata.

New checks rely on 2 invariants:

1) For frontend instrumentation, MD_prof branch_weights will always be
   populated before llvm.expect intrinsics are lowered.

2) for IR and sample profiling, llvm.expect intrinsics will always be
   lowered before branch_weights are populated from the IR profiles.

These invariants allow the checking to assume how the existing branch
weights are populated depending on the profiling method used, and emit
the correct diagnostics. If these invariants are ever invalidated, the
MisExpect related checks would need to be updated, potentially by
re-introducing MD_misexpect metadata, and ensuring it always will be
transformed the same way as branch_weights in other optimization passes.

Frontend based profiling is now enabled without using LLVM Args, by
introducing a new CodeGen option, and checking if the -Wmisexpect flag
has been passed on the command line.

Reviewed By: tejohnson

Differential Revision: https://reviews.llvm.org/D115907
2022-04-19 21:23:48 +00:00
Yaxun (Sam) Liu cac4e2fe25 [CUDA][HIP] Fix gpu.used.external
Rename gpu.used.external as __clang_gpu_used_external as ptxas does not
allow . in global variable name.

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

Reviewed by: Joseph Huber, Artem Belevich

Differential Revision: https://reviews.llvm.org/D123946
2022-04-18 23:10:31 -04:00
Michael Kruse 2d92ee97f1 Reapply "[OpenMP] Refactor OMPScheduleType enum."
This reverts commit af0285122f.

The test "libomp::loop_dispatch.c" on builder
openmp-gcc-x86_64-linux-debian fails from time-to-time.
See #54969. This patch is unrelated.
2022-04-18 21:56:47 -05:00
Michael Kruse af0285122f Revert "[OpenMP] Refactor OMPScheduleType enum."
This reverts commit 9ec501da76.

It may have caused the openmp-gcc-x86_64-linux-debian buildbot to fail.
https://lab.llvm.org/buildbot/#/builders/4/builds/20377
2022-04-18 14:38:31 -05:00
Michael Kruse 9ec501da76 [OpenMP] Refactor OMPScheduleType enum.
The OMPScheduleType enum stores the constants from libomp's internal sched_type in kmp.h and are used by several kmp API functions. The enum values have an internal structure, namely each scheduling algorithm (e.g.) exists in four variants: unordered, orderend, normerge unordered, and nomerge ordered.

This patch (basically a followup to D114940) splits the "ordered" and "nomerge" bits into separate flags, as was already done for the "monotonic" and "nonmonotonic", so we can apply bit flags operations on them. It also now contains all possible combinations according to kmp's sched_type. Deriving of the OMPScheduleType enum from clause parameters has been moved form MLIR's OpenMPToLLVMIRTranslation.cpp to OpenMPIRBuilder to make available for clang as well. Since the primary purpose of the flag is the binary interface to libomp, it has been made more private to LLVMFrontend. The primary interface for generating worksharing-loop using OpenMPIRBuilder code becomes `applyWorkshareLoop` which derives the OMPScheduleType automatically and calls the appropriate emitter function.

While this is mostly a NFC refactor, it still applies the following functional changes:
 * The logic from OpenMPToLLVMIRTranslation to derive the OMPScheduleType also applies to clang. Most notably, it now applies the nonmonotonic flag for non-static schedules by default.
 * In OpenMPToLLVMIRTranslation, the nonmonotonic default flag was previously not applied if the simd modifier was used. I assume this was a bug, since the effect was due to `loop.schedule_modifier()` returning `mlir::omp::ScheduleModifier::none` instead of `llvm::Optional::None`.
 * In OpenMPToLLVMIRTranslation, the nonmonotonic default flag was set even if ordered was specified, in breach to what the comment before citing the OpenMP specification says. I assume this was an oversight.

The ordered flag with parameter was not considered in this patch. Changes will need to be made (e.g. adding/modifying function parameters) when support for it is added. The lengthy names of the enum values can be discussed, for the moment this is avoiding reusing previously existing enum value names such as `StaticChunked` to avoid confusion.

Reviewed By: peixin

Differential Revision: https://reviews.llvm.org/D123403
2022-04-18 14:03:17 -05:00
Richard Smith b27430f9f4 Treat `std::move`, `forward`, etc. as builtins.
This is extended to all `std::` functions that take a reference to a
value and return a reference (or pointer) to that same value: `move`,
`forward`, `move_if_noexcept`, `as_const`, `addressof`, and the
libstdc++-specific function `__addressof`.

We still require these functions to be declared before they can be used,
but don't instantiate their definitions unless their addresses are
taken. Instead, code generation, constant evaluation, and static
analysis are given direct knowledge of their effect.

This change aims to reduce various costs associated with these functions
-- per-instantiation memory costs, compile time and memory costs due to
creating out-of-line copies and inlining them, code size at -O0, and so
on -- so that they are not substantially more expensive than a cast.
Most of these improvements are very small, but I measured a 3% decrease
in -O0 object file size for a simple C++ source file using the standard
library after this change.

We now automatically infer the `const` and `nothrow` attributes on these
now-builtin functions, in particular meaning that we get a warning for
an unused call to one of these functions.

In C++20 onwards, we disallow taking the addresses of these functions,
per the C++20 "addressable function" rule. In earlier language modes, a
compatibility warning is produced but the address can still be taken.

The same infrastructure is extended to the existing MSVC builtin
`__GetExceptionInfo`, which is now only recognized in namespace `std`
like it always should have been.

This is a re-commit of
  fc30901096,
  a571f82a50, and
  64c045e25b
which were reverted in
  e75d8b7037
due to a crasher bug where CodeGen would emit a builtin glvalue as an
rvalue if it constant-folds.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D123345
2022-04-17 13:26:16 -07:00
Vitaly Buka e75d8b7037 Revert "Treat `std::move`, `forward`, and `move_if_noexcept` as builtins."
Revert "Extend support for std::move etc to also cover std::as_const and"
Revert "Update test to handle opaque pointers flag flip."

It crashes on libcxx tests https://lab.llvm.org/buildbot/#/builders/85/builds/8174

This reverts commit fc30901096.
This reverts commit a571f82a50.
This reverts commit 64c045e25b.
2022-04-16 00:27:51 -07:00
Joseph Huber 984a0dc386 [OpenMP] Use new offloading binary when embedding offloading images
The previous patch introduced the offloading binary format so we can
store some metada along with the binary image. This patch introduces
using this inside the linker wrapper and Clang instead of the previous
method that embedded the metadata in the section name.

Differential Revision: https://reviews.llvm.org/D122683
2022-04-15 20:35:26 -04:00
Richard Smith fc30901096 Extend support for std::move etc to also cover std::as_const and
std::addressof, plus the libstdc++-specific std::__addressof.

This brings us to parity with the corresponding GCC behavior.

Remove STDBUILTIN macro that ended up not being used.
2022-04-15 16:31:39 -07:00
Richard Smith 64c045e25b Treat `std::move`, `forward`, and `move_if_noexcept` as builtins.
We still require these functions to be declared before they can be used,
but don't instantiate their definitions unless their addresses are
taken. Instead, code generation, constant evaluation, and static
analysis are given direct knowledge of their effect.

This change aims to reduce various costs associated with these functions
-- per-instantiation memory costs, compile time and memory costs due to
creating out-of-line copies and inlining them, code size at -O0, and so
on -- so that they are not substantially more expensive than a cast.
Most of these improvements are very small, but I measured a 3% decrease
in -O0 object file size for a simple C++ source file using the standard
library after this change.

We now automatically infer the `const` and `nothrow` attributes on these
now-builtin functions, in particular meaning that we get a warning for
an unused call to one of these functions.

In C++20 onwards, we disallow taking the addresses of these functions,
per the C++20 "addressable function" rule. In earlier language modes, a
compatibility warning is produced but the address can still be taken.

The same infrastructure is extended to the existing MSVC builtin
`__GetExceptionInfo`, which is now only recognized in namespace `std`
like it always should have been.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D123345
2022-04-15 14:09:45 -07:00
Eli Friedman 4802edd1ac Fix size of flexible array initializers, and re-enable assertions.
In D123649, I got the formula for getFlexibleArrayInitChars slightly
wrong: the flexible array elements can be contained in the tail padding
of the struct.  Fix the formula to account for that.

With the fixed formula, we run into another issue: in some cases, we
were emitting extra padding for flexible arrray initializers. Fix
CGExprConstant so it uses a packed struct when necessary, to avoid this
extra padding.

Differential Revision: https://reviews.llvm.org/D123826
2022-04-15 12:09:57 -07:00
Jan Svoboda 9d98f58959 [clang][CodeGen] NFCI: Use FileEntryRef
This patch removes use of the deprecated `DirectoryEntry::getName()` from clangCodeGen by using `{File,Directory}EntryRef` instead.

Reviewed By: bnbarham

Differential Revision: https://reviews.llvm.org/D123768
2022-04-15 15:16:17 +02:00
Eli Friedman 6cf0b1b3da Comment out assertions about initializer size added in D123649.
They're causing failures in LLVM test-suite.  Added some regression
tests that explain the issue.
2022-04-14 13:58:17 -07:00
Eli Friedman 5955a0f937 Allow flexible array initialization in C++.
Flexible array initialization is a C/C++ extension implemented in many
compilers to allow initializing the flexible array tail of a struct type
that contains a flexible array. In clang, this is currently restricted
to C. But this construct is used in the Microsoft SDK headers, so I'd
like to extend it to C++.

For now, this doesn't handle dynamic initialization; probably not hard
to implement, but it's extra code, and I don't think it's necessary for
the expected uses.  And we explicitly fail out of constant evaluation.

I've added some additional code to assert that initializers have the
correct size, with or without flexible array init. This might catch
issues unrelated to flexible array init.

Differential Revision: https://reviews.llvm.org/D123649
2022-04-14 11:56:40 -07:00
David Truby 53fd8db791 [Clang][AArch64][SVE] Allow subscript operator for SVE types
Undefined behaviour is just passed on to extract_element when the
index is out of bounds. Subscript on svbool_t is not allowed as
this doesn't really have meaningful semantics.

Differential Revision: https://reviews.llvm.org/D122732
2022-04-14 13:20:50 +01:00
Jan Svoboda d79ad2f1db [clang][lex] NFCI: Use FileEntryRef in PPCallbacks::InclusionDirective()
This patch changes type of the `File` parameter in `PPCallbacks::InclusionDirective()` from `const FileEntry *` to `Optional<FileEntryRef>`.

With the API change in place, this patch then removes some uses of the deprecated `FileEntry::getName()` (e.g. in `DependencyGraph.cpp` and `ModuleDependencyCollector.cpp`).

Reviewed By: dexonsmith, bnbarham

Differential Revision: https://reviews.llvm.org/D123574
2022-04-14 10:46:12 +02:00
joker881 a4f47a99aa RISCV] Add clang builtins for CLZ instruction.
add intrinsic for CLZ

Reviewed By: craig.topper

Differential Revision: https://reviews.llvm.org/D121915
2022-04-14 12:29:15 +08:00
Eli Friedman d791de0e25 Restrict lvalue-to-rvalue conversions in CGExprConstant.
We were generating wrong code for cxx20-consteval-crash.cpp: instead of
loading a value of a variable, we were using its address as the
initializer.

Found while adding code to verify the size of constant initializers.

Differential Revision: https://reviews.llvm.org/D123648
2022-04-13 12:34:57 -07:00
Erich Keane 38823b7f5f Fix Werror build issue from 6f20744b7f 2022-04-13 11:00:09 -07:00
Erich Keane 6f20744b7f Add support for ignored bitfield conditional codegen.
Currently we emit an error in just about every case of conditionals
with a 'non simple' branch if treated as an LValue.  This patch adds
support for the special case where this is an 'ignored' lvalue, which
permits the side effects from happening.

It also splits up the emit for conditional LValue in a way that should
be usable to handle simple assignment expressions in similar situations.

Differential Revision: https://reviews.llvm.org/D123680
2022-04-13 10:33:55 -07:00
Yaxun (Sam) Liu 0424b5115c [CUDA][HIP] Fix host used external kernel in archive
For -fgpu-rdc, a host function may call an external kernel
which is defined in an archive of bitcode. Since this external
kernel is only referenced in host function, the device
bitcode does not contain reference to this external
kernel, then the linker will not try to resolve this external
kernel in the archive.

To fix this issue, host-used external kernels and device
variables are tracked. A global array containing pointers
to these external kernels and variables is emitted which
serves as an artificial references to the external kernels
and variables used by host.

Reviewed by: Artem Belevich

Differential Revision: https://reviews.llvm.org/D123441
2022-04-13 10:47:16 -04:00
Nikita Popov 2978d02681 [Clang] Remove support for legacy pass manager
This removes the -flegacy-pass-manager and
-fno-experimental-new-pass-manager options, and the corresponding
support code in BackendUtil. The -fno-legacy-pass-manager and
-fexperimental-new-pass-manager options are retained as no-ops.

Differential Revision: https://reviews.llvm.org/D123609
2022-04-13 10:21:42 +02:00
Daniel Kiss b0343a38a5 Support the min of module flags when linking, use for AArch64 BTI/PAC-RET
LTO objects might compiled with different `mbranch-protection` flags which will cause an error in the linker.
Such a setup is allowed in the normal build with this change that is possible.

Reviewed By: pcc

Differential Revision: https://reviews.llvm.org/D123493
2022-04-13 09:31:51 +02:00
Quinn Pham 7d7022fb0c [PowerPC] Fix EmitPPCBuiltinExpr to emit arguments once
This patch changes `EmitPPCBuiltinExpr` in `CGBuiltin.cpp` to remove
the loop at the beginning of the function that emits the arguments and
to delay emitting the arguments until inside the switch statement. These
changes will put `EmitPPCBuiltinExpr` in line with the strategy of the
target independent function `EmitBuiltinExpr`. Also, this patch
ensures that arguments are only emitted once.

Tests that included builtins affected by these changes have been
modified to match expected behaviour.

Reviewed By: #powerpc, nemanjai, amyk

Differential Revision: https://reviews.llvm.org/D121637
2022-04-12 15:33:20 -05:00
Nikita Popov b72fd1a84d [CGCall] Check store type in findDominatingStoreToReturnValue()
We need to make sure that the stored type matches the return type.
2022-04-11 12:08:29 +02:00
Yaxun (Sam) Liu 4ea1d43509 [CUDA][HIP] Externalize kernels in anonymous name space
kernels in anonymous name space needs to have unique name
to avoid duplicate symbols.

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

Reviewed by: Artem Belevich

Differential Revision: https://reviews.llvm.org/D123353
2022-04-10 21:56:28 -04:00
Jonas Hahnfeld e4903d8be3 [CUDA/HIP] Remove argument from module ctor/dtor signatures
In theory, constructors can take arguments when called via .init_array
where at least glibc passes in (argc, argv, envp). This isn't used in
the generated code and if it was, the first argument should be an
integer, not a pointer. For destructors registered via atexit, the
function should never take an argument.

Differential Revision: https://reviews.llvm.org/D123370
2022-04-09 12:34:41 +02:00
Jennifer Yu 187ccc66fa [clang][OpenMP5.1] Initial parsing/sema for has_device_addr
Added basic parsing/sema/ support for the 'has_device_addr' clause.

Differential Revision: https://reviews.llvm.org/D123402
2022-04-08 21:19:38 -07:00
Mitch Phillips fa34951fbc Reland "[MTE] Add -fsanitize=memtag* and friends."
Differential Revision: https://reviews.llvm.org/D118948
2022-04-08 14:28:33 -07:00
Aaron Ballman 4aaf25b4f7 Revert "[MTE] Add -fsanitize=memtag* and friends."
This reverts commit 8aa1490513.

Broke testing: https://lab.llvm.org/buildbot/#/builders/109/builds/36233
2022-04-08 16:15:58 -04:00
Mitch Phillips 8aa1490513 [MTE] Add -fsanitize=memtag* and friends.
Currently, enablement of heap MTE on Android is specified by an ELF note, which
signals to the linker to enable heap MTE. This change allows
-fsanitize=memtag-heap to synthesize these notes, rather than adding them
through the build system. We need to extend this feature to also signal the
linker to do special work for MTE globals (in future) and MTE stack (currently
implemented in the toolchain, but not implemented in the loader).

Current Android uses a non-backwards-compatible ELF note, called
".note.android.memtag". Stack MTE is an ABI break anyway, so we don't mind that
we won't be able to run executables with stack MTE on Android 11/12 devices.

The current expectation is to support the verbiage used by Android, in
that "SYNC" means MTE Synchronous mode, and "ASYNC" effectively means
"fast", using the Kernel auto-upgrade feature that allows
hardware-specific and core-specific configuration as to whether "ASYNC"
would end up being Asynchronous, Asymmetric, or Synchronous on that
particular core, whichever has a reasonable performance delta. Of
course, this is platform and loader-specific.

Differential Revision: https://reviews.llvm.org/D118948
2022-04-08 12:13:15 -07:00
Nikita Popov 692a147bf4 [CGCall] Make findDominatingStoreToReturnValue() more robust
This was skipping specific lifetime + bitcast patterns, but with
opaque pointers the bitcast will not be present, and we did not
perform this fold.

Instead skip over lifetime.end and bitcasts generally, without
trying to correlate them.
2022-04-08 15:18:12 +02:00
serge-sans-paille 301e0d9135 [Clang][Fortify] drop inline decls when redeclared
When an inline builtin declaration is shadowed by an actual declaration, we must
reference the actual declaration, even if it's not the last, following GCC
behavior.

This fixes #54715

Differential Revision: https://reviews.llvm.org/D123308
2022-04-08 09:31:51 +02:00
Chuanqi Xu 74b56e02bd [NFC] Remove unused variable in CodeGenModules
This eliminates an unused-variable warning
2022-04-08 11:52:31 +08:00
David Blaikie 1cee3d9db7 DebugInfo: Consider the type of NTTP when simplifying template names
Since the NTTP may need to be cast to the type when rebuilding the name,
check that the type can be rebuilt when determining whether a template
name can be simplified.
2022-04-08 00:00:46 +00:00
Quinn Pham fef56f79ac Revert "[PowerPC] Fix EmitPPCBuiltinExpr to emit arguments once"
This reverts commit 2aae5b1fac. Because it
breaks tests on windows.
2022-04-07 16:45:19 -05:00
Quinn Pham 2aae5b1fac [PowerPC] Fix EmitPPCBuiltinExpr to emit arguments once
This patch changes `EmitPPCBuiltinExpr` in `CGBuiltin.cpp` to remove
the loop at the beginning of the function that emits the arguments and
to delay emitting the arguments until inside the switch statement. These
changes will put `EmitPPCBuiltinExpr` in line with the strategy of the
target independent function `EmitBuiltinExpr`. Also, this patch
ensures that arguments are only emitted once.

Tests that included builtins affected by these changes have been
modified to match expected behaviour.

Reviewed By: #powerpc, nemanjai, amyk

Differential Revision: https://reviews.llvm.org/D121637
2022-04-07 16:00:12 -05:00
Pavel Samolysov b4ac84901e [clang][NFC] Extract EmitAssemblyHelper::shouldEmitRegularLTOSummary
The code to check if the regular LTO summary should be emitted and to
add the corresponding module flags was duplicated in the
'EmitAssemblyHelper::EmitAssemblyWithLegacyPassManager' and
'EmitAssemblyHelper::RunOptimizationPipeline' methods.

In order to eliminate these code duplications, the
'EmitAssemblyHelper::shouldEmitRegularLTOSummary' method has been
extracted. The method returns a bool value, the value is 'true' if the
module summary should be emitted. The patch keeps the setting of the
module flags inline.

Reviewed By: tejohnson

Differential Revision: https://reviews.llvm.org/D123026
2022-04-07 10:38:46 -07:00
Kavitha Natarajan b1ea0191a4 [clang][DebugInfo] Support debug info for alias variable
clang to emit DWARF information for global alias variable as
DW_TAG_imported_declaration. This change also handles nested
(recursive) imported declarations.

Reviewed by: dblaikie, aprantl

Differential Revision: https://reviews.llvm.org/D120989
2022-04-07 17:15:40 +05:30
David Blaikie 6b306233f7 DebugInfo: Make the simplified template names prefix more unique 2022-04-06 18:25:46 +00:00
Ting Wang b389354b28 [Clang][PowerPC] Add max/min intrinsics to Clang and PPC backend
Add support for builtin_[max|min] which has below prototype:
A builtin_max (A1, A2, A3, ...)
All arguments must have the same type; they must all be float, double, or long double.
Internally use SelectCC to get the result.

Reviewed By: qiucf

Differential Revision: https://reviews.llvm.org/D122478
2022-04-05 22:43:48 -04:00
Tom Honermann 5531abaf71 [clang] Corrections for target_clones multiversion functions.
This change merges code for emit of target and target_clones multiversion
resolver functions and, in doing so, corrects handling of target_clones
functions that are declared but not defined. Previously, a use of such
a target_clones function would result in an attempted emit of an ifunc
that referenced an undefined resolver function. Ifunc references to
undefined resolver functions are not allowed and, when the LLVM verifier
is not disabled (via '-disable-llvm-verifier'), resulted in the verifier
issuing a "IFunc resolver must be a definition" error and aborting the
compilation. With this change, ifuncs and resolver function definitions
are always emitted for used target_clones functions regardless of whether
the target_clones function is defined (if the function is defined, then
the ifunc and resolver are emitted regardless of whether the function is
used).

This change has the side effect of causing target_clones variants and
resolver functions to be emitted in a different order than they were
previously. This is harmless and is reflected in the updated tests.

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D122958
2022-04-05 19:50:22 -04:00
Tom Honermann 40af8df6fe [clang] NFC: Preparation for merging code to emit target and target_clones resolvers.
This change modifies CodeGenModule::emitMultiVersionFunctions() in preparation
for a change that will merge support for emitting target_clones resolvers into
this function. This change mostly serves to isolate indentation changes from
later behavior modifying changes.

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D122957
2022-04-05 19:50:22 -04:00
Tom Honermann 0ace0100ae [clang] NFC: Simplify the interface to CodeGenModule::GetOrCreateMultiVersionResolver().
Previously, GetOrCreateMultiVersionResolver() required the caller to provide
a GlobalDecl along with an llvm::type and FunctionDecl. The latter two can be
cheaply obtained from the first, and the llvm::type parameter is not always
used, so requiring the caller to provide them was unnecessary and created the
possibility that callers would pass an inconsistent set. This change simplifies
the interface to only require the GlobalDecl value.

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D122956
2022-04-05 19:50:22 -04:00