282173 Commits

Author SHA1 Message Date
Sam Tebbs
8be3fc0f5c [AArch64] Disallow vscale x 1 partial reductions (#125252)
We don't want to allow partial reductions resulting in a vscale x 1 type
as we can't lower it in the backend.

(cherry picked from commit c7995a6905f2320f280013454676f992a8c6f89f)
2025-02-05 14:37:39 +00:00
Oliver Stannard
184d1783db [AArch64] PAUTH_PROLOGUE should not be duplicated with PAuthLR (#124775)
When using PAuthLR, the PAUTH_PROLOGUE expands into a sequence of
instructions which takes the address of one of those instructions, and
uses that address to compute the return address signature. If this is
duplicated, there will be two different addresses used in calculating
the signature, so the epilogue will only be correct for (at most) one of
them.

This change also restricts code generation when using v8.3-A return
address signing, without PAuthLR. This isn't strictly needed, as
duplicating the prologue there would be valid. We could fix this by
having two copies of PAUTH_PROLOGUE, with and without isNotDuplicable,
but I don't think it's worth adding the extra complexity to a security
feature for that.

(cherry picked from commit 36b3c43524c8ca86a5050496b8773f07c5ccddff)
2025-01-31 17:55:58 -08:00
Yingwei Zheng
40ca089d99 [CodeGenPrepare] Replace deleted ext instr with the promoted value. (#71058)
This PR replaces the deleted ext with the promoted value in `AddrMode`.
Fixes #70938.

(cherry picked from commit 3c6aa04cf4dee65113e2a780b9f90b36bb4c4e04)
2025-01-31 17:49:18 -08:00
David Green
b23297a7f1 [GlobalISel] Do not run verifier after ResetMachineFunctionPass (#124799)
After we fall back from GlobalISel to SDAG, the verifier gets called,
which calls getReservedRegs which uses SIMachineFunctionInfo::usesAGPRs
which caches the result of UsesAGPRs. Because we have just fallen-back
the function is empty and it incorrectly gets cached to false. This
patch makes sure we don't try to run the verifier whilst the function is
empty.

(cherry picked from commit 66e0498dafbfa7f8fd7deaa88ae62bdf38a12113)
2025-01-31 16:38:42 -08:00
Nikita Popov
fa12df5e22 [SCEV] Check correct value for UB (#124302)
This is a followup to #117152. That patch introduced a check for
UB/poison on BEValue. However, the SCEV we're actually going to use is
Shifted. In some cases, it's possible for Shifted to contain UB, while
BEValue doesn't.

In the test case the values are:

BEValue: (-1 * (zext i8 (-83 + ((-83 /u {1,+,1}<%loop>) *
{-1,+,-1}<%loop>)) to i32))<nuw><nsw>
Shifted: (-173 + (-1 * (zext i8 ((-83 /u {0,+,1}<%loop>) *
{0,+,-1}<%loop>) to i32))<nuw><nsw>)<nuw><nsw>

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

(cherry picked from commit 07efe2c18a63423943a4f9d9daeada23601f84c8)
2025-01-30 14:05:10 -08:00
Tom Stellard
a97eed928f
Bump version to 20.1.0git (#125067) 2025-01-30 13:54:53 -08:00
Thurston Dang
fdadef9be3
[msan] Handle x86_avx512_(min|max)_p[sd]_512 intrinsics (#124421)
The AVX/SSE variants are already handled heuristically (maybeHandleSimpleNomemIntrinsic via handleUnknownIntrinsic), but the AVX512 variants contain an additional parameter (the rounding method) which fails to match heuristically. This patch generalizes maybeHandleSimpleNomemIntrinsic to allow additional flags (ignored by MSan) and explicitly call it to handle AVX512 min/max ps/pd intrinsics.

It also updates the test added in https://github.com/llvm/llvm-project/pull/123980
2025-01-28 19:12:44 -08:00
Luke Lau
ff271d04a2
[RISCV][VLOPT] Fix assertion failure across blocks (#124734)
Whilst adding a cross-block test, I encountered an assertion failure in
the second pass where we check the instruction popped off the worklist
is a candidate.

The leaf instruction %c in this case will be added to the worklist when
its VL is VLMAX, but during the first pass it will have its VL reduced
to 1.

Then in the second pass when its processed via the worklist, isCandidate
will no longer be true due to its VL == 1.

This fixes it by moving the VL == 1 check to tryReduceVL, keeping it
alongside the other VL check for bailing out early as an optimisation.
2025-01-29 11:00:50 +08:00
Lang Hames
d0052ebbe2 [ORC][LLJIT] Install eh-frame registration plugin during platform setup.
Attempt to install the EHFrameRegistrationPlugin during GenericLLVMIRPlatform
setup, rather than object linking layer creation time.

Platform classes are responsible for exception handling: installing the plugin
unconditionally during linking-layer construction could result in frames being
registered more than once when native platform classes are used.

This is a precursor to re-landing compact unwind support (4f0325873fa).
2025-01-29 02:28:49 +00:00
vporpo
79cbad188a
[SandboxVec] Clear Context's state within runOnFunction() (#124842)
`sandboxir::Context` is defined at a pass-level scope with the
`SandboxVectorizerPass` class because the function pass manager `FPM`
object depends on it, and that is in pass-level scope to avoid
recreating the pass pipeline every single time `runOnFunction()` is
called.

This means that the Context's state lives on across function passes. The
problem is twofold:
(i) the LLVM IR to Sandbox IR map can grow very large including objects
from different functions, which is of no use to the vectorizer, as it's
a function-level pass.
(ii) this can result in stale data in the LLVM IR to Sandbox IR object
map, as other passes may delete LLVM IR objects.

To fix both issues this patch introduces a `Context::clear()` function
that clears the `LLVMValueToValueMap`.
2025-01-28 18:28:08 -08:00
Veera
98d6dd3988
[LLVM][LangRef][noalias] Remove Redundant Line and Improve Wording (#124685)
Removes a redundant line and improves punctuation and wording in the
paragraph describing the `noalias` attribute.
2025-01-28 20:21:22 -05:00
Thurston Dang
b8cdc5ea27
Reapply "[msan] Add avx512-intrinsics.ll and avx512-intrinsics-upgrade.ll test case (#123980)" (#124500)
This reverts commit b2647ffbf797dd5a457b6b19faab06956934d067 i.e.,
relands 980e86f130.

I had reverted the original patch because of buildbot failures (e.g., https://lab.llvm.org/buildbot/#/builders/13/builds/4938/steps/5/logs/FAIL__LLVM__avx512-intrinsics-upgrade_ll). This reland addresses the likely root cause; namely, that the target datalayout had not been specified.

Additionally, this reland improves the test case by replacing undef with extra parameters.
2025-01-28 15:29:21 -08:00
yonghong-song
8aae191cb6
[BPF] Remove 'may_goto 0' instructions (#123482)
Emil Tsalapatis from Meta reported such a case where 'may_goto 0' insn
is generated by clang compiler. But 'may_goto 0' insn is actually a
no-op so it makes sense to remove that in llvm. The patch is also able
to handle the following code pattern
```
   ...
   may_goto 2
   may_goto 1
   may_goto 0
   ...
```
where three may_goto insns can all be removed.

---------

Co-authored-by: Yonghong Song <yonghong.song@linux.dev>
2025-01-28 15:19:05 -08:00
Prabhuk
e7f02241ad
[nfc][llvm] Clean up isUEFI checks (#124845)
The check for `isOSWindows() || isUEFI()` is used in several places
across the codebase. Introducing `isOSWindowsOrUEFI()` in Triple.h
to simplify these checks.
2025-01-28 15:18:10 -08:00
Raphael Kubo da Costa
437040fe3d
[CMake] Use shm_open, not clock_gettime, to detect librt (#120727)
On systems with glibc, clock_gettime() was moved from librt to libc in
version 2.17, in which case the current librt detection attempt would
always fail.

Look for shm_open instead, like other parts of the tree also do when
looking for librt.

Co-authored-by: Raphael Kubo da Costa <kubo@igalia.com>
2025-01-28 15:17:45 -08:00
gulfemsavrun
38902153fe
[PassBuilder] Add RelLookupTableConverterPass to LTO (#124053)
[PassBuilder] Add RelLookupTableConverterPass to LTO

This patch adds RelLookupTableConverterPass into the LTO
post-link optimization pass pipeline. This optimization
converts lookup tables to relative lookup tables to make
them PIC-friendly, which is already included in the non-LTO
pass pipeline. This patch adds this optimization to the
post-link optimization pipeline to discover more
opportunities in the LTO context.
2025-01-28 15:08:03 -08:00
Thurston Dang
4a426079d6
[msan] Use horizontal add to compute shadow for horizontal sub (#124835)
This improves the horizontal sub handling (from
https://github.com/llvm/llvm-project/pull/124159), by always using
horizontal add for the shadow, as recommended by Vitaly.

Fixes https://github.com/llvm/llvm-project/issues/124662
2025-01-28 14:56:05 -08:00
goldsteinn
c2fba02347
[ValueTracking] Fix bug of using wrong condition for deducing KnownBits (#124481)
- **[ValueTracking] Add test for issue 124275**
- **[ValueTracking] Fix bug of using wrong condition for deducing
KnownBits**

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

Bug was introduced by https://github.com/llvm/llvm-project/pull/114689

Now that computeKnownBits supports breaking out of recursive Phi
nodes, `IncValue` can be an operand of a different Phi than `P`. This
breaks the previous assumptions we had when using the possibly
condition at `CxtI` to constrain `IncValue`.
2025-01-28 15:54:00 -06:00
Florian Hahn
6338bde568
[VPlan] Use cast<VPRecipeBase> in verifier (NFC).
All users of VPValue must be a VPRecipeBase, use cast.
2025-01-28 21:01:02 +00:00
Thurston Dang
7bd9c780e3
[msan][NFCI] Generalize handleIntrinsicByApplyingToShadow to allow alternative intrinsic for shadows (#124831)
https://github.com/llvm/llvm-project/pull/124159 uses
handleIntrinsicByApplyingToShadow for horizontal add/sub, but Vitaly
recommends always using the add version to avoid false negatives for
fully uninitialized data
(https://github.com/llvm/llvm-project/issues/124662).

This patch lays the groundwork by generalizing
handleIntrinsicByApplyingToShadow to allow using a different intrinsic
(of the same type as the original intrinsic) for the shadow. Planned
work will apply it to horizontal sub.
2025-01-28 12:35:07 -08:00
Kazu Hirata
1d5ce614a7
[CodeGen] Avoid repeated hash lookups (NFC) (#124677) 2025-01-28 10:57:29 -08:00
Stephen Tozer
822f74a911
[Clang] Cleanup docs and comments relating to -fextend-variable-liveness (#124767)
This patch contains a number of changes relating to the above flag;
primarily it updates comment references to the old flag names,
"-fextend-lifetimes" and "-fextend-this-ptr" to refer to the new names,
"-fextend-variable-liveness[={all,this}]". These changes are all NFC.

This patch also removes the explicit -fextend-this-ptr-liveness flag
alias, and shortens the help-text for the main flag; these are both
changes that were meant to be applied in the initial PR (#110000), but
due to some user-error on my part they were not included in the merged
commit.
2025-01-28 18:25:32 +00:00
Brad Smith
cfdd937b30
[llvm] Android has sched_getaffinity() now (#124689) 2025-01-28 13:21:14 -05:00
Thurston Dang
063db51cd4 Reapply "[msan] Add handlers for AVX masked load/store intrinsics (#123857)"
This reverts commit b9d301cc7e4fe4c442ec15169686fa4a18f5cdfc i.e.,
relands db79fb2a91df31a07f312f8e061936927ac5c506.

I had mistakenly thought this caused a buildbot breakage (the actual
culprit was my other patch,
https://github.com/llvm/llvm-project/pull/123980, which landed at the
same time) and thus had reverted it even though AFAIK it is not broken.
2025-01-28 18:11:44 +00:00
Alexey Bataev
947d8ebbf3
[SLP]Unify getNumberOfParts use
Adds getNumberOfParts and uses it instead of similar code across code
base, fixes analysis of non-vectorizable types in
computeMinimumValueSizes.

Reviewers: RKSimon

Reviewed By: RKSimon

Pull Request: https://github.com/llvm/llvm-project/pull/124774
2025-01-28 12:16:44 -05:00
Ramkumar Ramachandra
d76ea250c8
Reland [InstCombine] Teach foldSelectOpOp about samesign (#124320)
Changes: There was a serious bug in the previous patch, leading to a
miscompile. See #122723 for the miscompile report from Alexander, and
the follow-up investigation by Nikita. The patch has since been
reworked, and now includes the testcase from the miscompile.

Follow up on 4a0d53a (PatternMatch: migrate to CmpPredicate) to get rid
of one of the FIXMEs it introduced by replacing a predicate comparison
with CmpPredicate::getMatching.

Co-authored-by: Nikita Popov <npopov@redhat.com>
2025-01-28 16:53:01 +00:00
Thurston Dang
ef92e6b99f
[BoundsChecking] Update ubsantrap to use GuardKind (#124613)
This change makes it consistent with other uses of ubsantrap.

This also updates the tests. Notably, BoundsChecking/runtimes.ll had guard=3 which passed only because the method of calculating the parameter (`IRB.GetInsertBlock()->getParent()->size()`) happened to give the same answer.
2025-01-28 08:52:31 -08:00
c8ef
f388ca3d9d
[NFC] Remove redundant sys/file.h header. (#124684)
Closes #124652.

This header was introduced in
536736995b,
but it appears that including only `fnctl.h` should be enough.
Hopefully, this patch will not cause build issues on other Unix
platforms.
2025-01-29 00:50:24 +08:00
Vyacheslav Levytskyy
df122fc734
[SPIR-V] Change a way SPIR-V Backend API works with user facing options (#124745)
This PR fixes https://github.com/llvm/llvm-project/issues/124703:
* added a new API call `SPIRVTranslate` that is to replace entirely old
`SPIRVTranslateModule` after existing clients switch into the new
function;
* the new `SPIRVTranslate` doesn't require option parsing, replacing the
`Opts` argument with explicit `CodeGenOptLevel` and `Triple` arguments;
* the old `SPIRVTranslateModule` call is a wrapper for `SPIRVTranslate`,
it doesn't require option parsing either and doesn't hold any logic
inside except for converting string options into `CodeGenOptLevel` and
`Triple` arguments;
* usage of the extensions list is reworked to avoid writes to the global
cl::opt variable `lib/Target/SPIRV/SPIRVSubtarget.cpp::Extensions` --
instead a new class member in SPIRVSubtarget.cpp is implemented that
allows to replace supported extensions after SPIRVSubtarget.cpp is
created;
* both API calls don't require option parsing and don't write to global
cl::opt variables.

Other related/required changes:
* SPIRV::Capability::Shader is marked as an capability of lesser
priority for OpenCL environment (to remediate absence of the
"avoid-spirv-capabilities" command line option in API calls);
* unit tests are updated and extended to cover testing of a newer API
call;
* old API call is marked with TODO to remove it after existing clients
switch into the new function.
2025-01-28 17:33:11 +01:00
Jeremy Morse
48df9480da
[NFC] Suppress spurious deprecation warning with MSVC (#124764)
gcc and clang won't complain about calls to deprecated functions, if
you're calling from a function that is deprecated too. However, MSVC
does care, and expands into maaany deprecation warnings for
getFirstNonPHI.

Suppress this by converting the inlineable copy of getFirstNonPHI into a
non-inline copy.
2025-01-28 15:55:45 +00:00
Mats Jun Larsen
d459784cbe
[IR][SPIR-V] Replace of PointerType::get(Type) with opaque version (NFC) (#124755) 2025-01-28 15:44:45 +00:00
Venkata Ramanaiah Nalamothu
a0b049055d
[RISC-V] Fix incorrect epilogue_begin setting in debug line table (#120623)
The DwarfDebug.cpp implementation expects the epilogue instructions to
have source location of last non-debug instruction after which the epilogue
instructions are inserted. The epilogue_begin is set on location of the first
FrameDestroy instruction with source line information that has been seen in
the epilogue basic block.

In the trunk, the risc-v backend sets the epilogue_begin after the epilogue has
actually begun i.e. after callee saved register reloads and the source line
information is not set on those reload instructions. This is leading to #120553
where, while debugging, breaking on or single stepping to the epilogue_begin
location will make accessing the variables from wrong place as the FP has been
restored to the parent frame's FP.

To fix that, this patch sets FrameSetup/FrameDestroy flags on the callee saved
register spill/reload instructions which is actually correct. Then the
RISCVInstrInfo::loadRegFromStackSlot uses FrameDestroy flag to identify a
reload of the callee saved register in the epilogue and copies the source
line information from insert position instruction to that reload instruction.

Requires PR #120622

Fixes #120553
2025-01-28 21:03:12 +05:30
LLVM GN Syncbot
2abde54aab [gn build] Port de4bbbfdccb6 2025-01-28 15:05:54 +00:00
Simon Pilgrim
7d172f96ff
[CostModel][X86] getShuffleCosts - convert all shuffle cost tables to be CostKind compatible. NFC. (#124753)
No change in actual costs yet, but split the costs per cost kind to make it easier to tweak the numbers in future patches.
2025-01-28 15:04:25 +00:00
Daniil Fukalov
68d90cff58
[AMDGPU][GlobalISel] Fix assert on APInt creation. (#124608)
Since 3494ee95902cef62f767489802e469c58a13ea04 APInt stopped to
implicitly truncate values, therefore it asserts on a big signed value
converted to (implicitly) unsigned APInt.

The change explicitly marks offset as a signed value.
2025-01-28 15:53:17 +01:00
Matt Arsenault
ee1c6a6bc1 MachineVerifier: Move test into AMDGPU directory
Fixes failures for builds without AMDGPU enabled for test
added in 11db7fb09b36e656a801117d6a2492133e9c2e46
2025-01-28 21:36:23 +07:00
Florian Hahn
3007f31e74 [LoopUnroll] Add AArch64 tests for multi-exit loop unrolling.
Test coverage to https://github.com/llvm/llvm-project/pull/124751.
2025-01-28 14:25:27 +00:00
Nico Weber
3a975d697f [gn] port 7e22180c20f (BuiltinsHexagon.td) 2025-01-28 06:14:22 -08:00
Jeremy Morse
79499f010d [NFC][DebugInfo] Deprecate iterator-taking moveBefore and getFirstNonPHI (#124290)
The RemoveDIs project [0] makes debug intrinsics obsolete and to support
this instruction iterators carry an extra bit of debug information. To
maintain debug information accuracy insertion needs to be performed with a
BasicBlock::iterator rather than with Instruction pointers, otherwise the
extra bit of debug information is lost.

To that end, we're deprecating getFirstNonPHI and moveBefore for
instruction pointers. They're replaced by getFirstNonPHIIt and an
iterator-taking moveBefore: switching to the replacement is
straightforwards, and 99% of call-sites need only to unwrap the iterator
with &* or call getIterator() on an Instruction pointer.

The exception is when inserting instructions at the start of a block: if
you call getFirstNonPHI() (or begin() or getFirstInsertionPt()) and then
insert something at that position, you must pass the BasicBlock::iterator
returned into the insertion method. Unwrapping with &* and then calling
getIterator strips the debug-info bit we wish to preserve. Please do
contact us about any use case that's confusing or unclear [1].

[0] https://llvm.org/docs/RemoveDIsDebugInfo.html
[1] https://discourse.llvm.org/t/psa-ir-output-changing-from-debug-intrinsics-to-debug-records/79578
2025-01-28 14:02:24 +00:00
Alexey Bataev
a1ab5b4c87 [SLP]Check the MainOp matches the requirements for the instructions
Need to include MainOp into the analysis of the instructions in
getSameOpcode to be sure that it is checked for the requirements to
prevent crashes during further analysis.
2025-01-28 06:00:52 -08:00
Stephen Tozer
22687aa97b
[CodeGen] Correctly handle non-standard cases in RemoveLoadsIntoFakeUses (#111551)
In the RemoveLoadsIntoFakeUses pass, we try to remove loads that are
only used by fake uses, as well as the fake use in question. There are
two existing errors with the pass however: it incorrectly examines every
operand of each FAKE_USE, when only the first is relevant (extra
operands will just be "killed" regs assigned by a previous pass), and it
ignores cases where the FAKE_USE register is not an exact match for the
loaded register, which is incorrect as regalloc may choose to load a
wider value than the FAKE_USE required pre-regalloc. This patch fixes
both of these cases.
2025-01-28 13:59:41 +00:00
Nico Weber
37b595cb37 [gn] port b968fd950266 (BuiltinsNVPTX.td) 2025-01-28 05:57:06 -08:00
Renat Idrisov
11db7fb09b
[GlobalISel] Catching inconsistencies in load memory, result, and range metadata type (#121247)
This is a fix for:
https://github.com/llvm/llvm-project/issues/97290
Please let me know if that is the right way to address the issue. Thank
you!

---------

Co-authored-by: Renat Idrisov <parsifal-47@users.noreply.github.com>
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
2025-01-28 20:54:34 +07:00
Alexey Bataev
1d5fbe83c3 [SLP]Adjust NumberOfParts value for adjusted number of buildvector scalars
Need to adjust NumParts value, when GatheredScalars scalars are adjusted
after extractelements analysis, to fix compiler crash
2025-01-28 05:45:13 -08:00
Joseph Huber
13dcc95dcd
[Offload] Rework offloading entry type to be more generic (#124018)
Summary:
The previous offloading entry type did not fit the current use-cases
very well. This widens it and adds a version to prevent further
annoyances. It also includes the kind to better sort who's using it.

The first 64-bytes are reserved as zero so the OpenMP runtime can detect
the old format for binary compatibilitry.
2025-01-28 07:26:13 -06:00
abhishek-kaushik22
015aed18ee
[SelectionDAG] WidenVecOp_INSERT_SUBVECTOR - Replace INSERT_SUBVECTOR with series of INSERT_VECTOR_ELT (#124420)
If the operands to `INSERT_SUBVECTOR` can't be widened legally, just
replace the `INSERT_SUBVECTOR` with a series of `INSERT_VECTOR_ELT`.

Closes #124255 (and possibly #102016)
2025-01-28 18:54:49 +05:30
Alex Bradbury
606cf88741
[ExecutionEngine][test][RISCV] Don't mark RISCV as unsupported (#124464)
Although MCJIT is unsupported, we can and should be running the other
tests. Stacks on top of #124463 (needed to avoid unsupported MCJIT tests
in the top-level test/ExecutionEngine directory running when they
shouldn't).

This effectively reverts b8feeba0b407e703385738af7e415d0c8972a420.

ninja check-llvm-executionengine before:
Total Discovered Tests: 335
  Unsupported: 335 (100.00%)

ninja check-llvm-executionengine after:
Total Discovered Tests: 335
  Unsupported      : 125 (37.31%)
  Passed           : 209 (62.39%)
  Expectedly Failed:   1 (0.30%)
2025-01-28 13:23:40 +00:00
Alex Bradbury
62c16d8219
[MCJIT][test] Move MCJIT non-interpreter tests to MCJIT subdirectory (#124463)
Moving to the MCJIT subdirectory means they can be gated by a common
lit.local.cfg. I remove the `; UNSUPPORTED: target=loongarch{{.*}}`
lines because of this (as the logic in `MCJIT/lit.local.cfg` should be
sufficient).

The move is motivated by my desire to enable more of these tests for
RISCV, and it seems like it would be wrong to keep extending the
`UNSUPPORTED` lines for these individual tests.

This patch does not move the MCJIT tests in the top-level directory that
do `-force-interpreter=true`.
2025-01-28 13:13:42 +00:00
Mészáros Gergely
e1b5826c2b
[LLVM][CMake][MSVC] Wrap linker options for ICX with LLVM_BUILD_INSTUMENTED (#124573)
RFC:
https://discourse.llvm.org/t/rfc-cmake-linker-flags-need-wl-equivalent-for-intel-c-icx-on-windows/82446

The Intel C++ Compiler (ICX) passes linker flags through the driver
unlike MSVC and clang-cl, and therefore needs them to be prefixed with
`/Qoption,link` (the equivalent of `-Wl,` for gcc on *nix).

Previous PRs did not catch this because I did not try building with
`LLVM_BUILD_INSTRUMENTED=ON`.
`CMAKE_CXX_LINKER_WRAPPER_FLAG` is empty for plain clang-cl (icx on
windows behaves as clang-cl), so this is NFC for clang-cl.
2025-01-28 13:49:37 +01:00
Luke Lau
500a1834d9 [RISCV][VLOPT] Fix some typos in vl-opt-op-info.mir test. NFC
vleN_v_incompatible_emul reassigns to %x and
vsuxeiN_v_idx_incompatible_eew has a dead instruction
2025-01-28 20:28:02 +08:00