[SLP]Release all lanes of a repeated copyable element in scheduling
A copyable element in several lanes of one node may sit in different
operand columns per lane. Scheduling released only the first lane, and
the chain self-use check looked at one lane, so a direct use from
another lane kept the operand unscheduled.
Fixes #241483
Pull-request: https://github.com/llvm/llvm-project/pull/241539
[LV] Add tests for fmaxnum reduction with ALM tail folding (NFC). (#241522)
Add tests for FMaxNum reductions with tail folding using the
active-lane-mask for control flow. Currently mis-compiled.
Keep the local key where a raw receive brings a foreign one
A raw receive writes the DSL Crypto Key from the stream over the one on
disk but leaves the encryption root it is filed under alone. The key in
the stream is wrapped by the wrapping key of the sender's encryption
root, so this only holds together for as long as ours is the same one.
Where the receiving filesystem inherits from a root with a wrapping key
of its own, which is what a replica has once 'zfs change-key -i' hands
it to a locally keyed dataset, the wrapped master key on disk becomes
the sender's while the root it is filed under is still ours, and nothing
on the pool can unwrap it. The unwrapped key stays cached until it is
unloaded, so the receive and everything after it look fine; the next
'zfs load-key' loads the root happily and the filesystem then refuses to
mount with EACCES. Getting the data back takes the sending pool's
wrapping key and a hand built encryption hierarchy, which is why
reporters have ended up rebuilding their backups instead.
The keyformat, salt and iteration count travel with the key and describe
the wrapping key it was wrapped with, so where the receiving filesystem
[30 lines not shown]
Thread Safety Analysis: Carry a loop-checked try-acquire result out of the loop
A loop's exit edges were computed from the head's exit set as analyzed on
the first iteration, before the body's try-acquire result existed. An
iteration that acquires the capability and keeps the result -- the loop
checks it, so the loop join says nothing -- therefore left the loop
invisibly: neither the code after the loop nor the end of the function
saw the possible hold.
The back-edge patch that already carried a released result into those
sealed exit sets now carries such a result too. The code after the loop
is read against the possibility: `if (ok) mu.Unlock();` resolves it and
is clean, a bare release is "may not be held" rather than "was not
held", a blocking acquire is "may already be held", and where nothing
resolves it, -Wthread-safety-beta reports the leak at the end of the
function. The first three are plain -Wthread-safety: the patch is not
beta-gated, and a loop that may leave a capability held is a fact about
the code, not about a diagnostic mode. Two shapes in the existing tests
move that way, and one C++ test gains the beta report.
[40 lines not shown]
Thread Safety Analysis: Track a cross-kind try-acquire as one try fact
per kind
A call promising a capability exclusively on one outcome and shared on
another (`int TryLockCross() TRY_ACQUIRE(2, mu) TRY_ACQUIRE_SHARED(0, mu)`,
kept conditional because the codes do not cover an int result's domain)
tracked one conditional try fact of the weaker kind: a try fact carries
one kind, and the outcome that decides which attribute applies is only
known per edge. The edge promising the exclusive hold therefore granted
only a shared one, and an exclusive write under it was diagnosed.
A try fact is identified by its capability, its originating call and its
lock kind (TryFactEntry), so a call promising both kinds can have one of
each: handleCall() creates one try fact per kind the call promises the
capability in, and each resolves by its own kind's attributes. Everything
the resolution reads is keyed by kind for that: getCapProfile() takes the
kind and reads only that kind's polarity groups, and the exact codes and
any-nonzero promises the record keeps are tagged with the kind that made
them -- reading across the kinds granted one kind's hold on the edge where
[47 lines not shown]
Thread Safety Analysis: Bound a loop's checked results by dominance
A try-acquire whose result is branched on somewhere in a loop is not
reported unchecked at that loop's join: the loop checks it, on this
iteration or the next. Which blocks count as being in the loop was
decided by two different walks. The injection bounded its backward walk
from the latch by the blocks the head reaches forwards; the
checked-result scan did not bound it at all, so a goto into the body let
it walk out of the loop and collect a check made before the jump. That
is now one walk, collectNaturalLoop(), which checkBackEdges() runs once
for both phases, and its bound is dominance.
Dominance is the textbook bound, and the only one that survives nesting:
forward reachability from the head runs round an enclosing loop's back
edge and reaches the pre-loop blocks again, so for any loop inside
another cycle it excluded nothing. It is also what makes sharing the
walk affordable. Recomputing the head's forward reach costs the whole
function per back edge; clang::CFGDomTree is built once per function, on
demand, and answers in constant time. On N sequential `while` loops
[35 lines not shown]
Thread Safety Analysis: Split runAnalysis() into its phases [NFC]
runAnalysis() had grown past four hundred lines around the try-acquire
machinery. Its phases are now functions: addDeclaredLocksets() builds
the initial and expected-exit locksets from the function's attributes
(and says which functions the analysis skips), joinPredecessors()
computes a block's entry set from its predecessors, including the
infeasible-edge and coverage-only handling, visitBlock() walks the
block's elements, and checkBackEdges() compares each back edge against
its loop head and patches the loop's exit sets. The block loop itself
is the phase sequence.
injectLoopReleasedTryFacts() splits around its own natural-loop walk:
collectInjectableTryFacts() reads the release evidence out of the
latch's exit set, collectNaturalLoop() is the walk -- backwards from the
latch, bounded by what the head reaches forwards, so a second entry into
the body cannot let it escape the loop -- and patchLoopExitSets() writes
the evidence into the exit sets the loop's exit edges are computed from.
checkBackEdges() walks only when the latch carries evidence to patch, as
[36 lines not shown]
Thread Safety Analysis: Resolve try-acquire results by exact value, not
just truthiness
The attributes' success values, the branch conditions on the result,
and the resolution between them all collapsed to truthiness, which is
unsound in both directions for attributes keying distinct capabilities
to integer codes:
int trylock_codes() TRY_ACQUIRE(1, mu1) TRY_ACQUIRE(2, mu2);
`if (trylock_codes() == 2)` silently accepted uses of mu1 in its body
("truthy" promoted it too, though a result of 2 proves mu1 was never
acquired), and the other edge of `== 1` read as "result falsy", wrongly
removing mu2's fact.
Design details:
* Recording: a truthy success value keys the acquisition to that exact
result value (ExactCodes), computed by the constant evaluator so that
[110 lines not shown]
Thread Safety Analysis: Demote same-origin joins silently
A join can bring together two outcomes of one try-acquire: the hold its
success proved on one path and the record of its failure on the other.
Both sides denote "held iff the call's result", so their join is the
call's conditional try fact, and diagnosing a lost hold there reports a
loss that did not happen. intersectAndWarn() now demotes such
same-origin joins to that conditional try fact instead, silently. These
are the same-origin cells of the try fact lattice (Conditional meeting
ProvedNotHeld, ProvedHeld meeting ProvedNotHeld, and at an unsealed loop
join Conditional meeting ProvedHeld), which the join had so far refused:
a policy gate now opens them.
Design details:
* One predicate decides how a hold survives a join (holdDemotion): the
terminator rebranches on the call that proved it, so the outgoing
edges re-resolve it -- unless that call's stale result on the other
side vetoes the premise -- or else the other side carries the call's
[88 lines not shown]
Thread Safety Analysis: Resolve try-acquire results merged by a
conditional operator
A non-void `?:` on a try-acquire result used to pin it unresolved
wholesale: the branch was never honored, and only a both-arms-constant
value (`ok ? 1 : 0`) could be decoded at a later branch. The body of
`if (mu.TryLock() ? use() : false)` warned although a truthy value
proves the lock is held, and the GNU form `ok ?: 0` was not decoded at
all. Now the decode computes what the merged value determines about
the result, arm by arm, and the `?:` terminator itself is always
honored as a branch.
Design details:
* With both arms constant, the value the condition selects is one of
them: its magnitude is the arm's, so exact values are never applied
to the result (a new ValueMerged flag clears ValueIsResult), while
what the branch asks of that value decides the condition. A
comparison against an arm's own constant is satisfied exactly when
[89 lines not shown]
Thread Safety Analysis: Resolve branches on stored try-acquire results
through merges and phis
The common guard pattern
bool ok = false;
if (cond)
ok = mu.TryLock();
if (ok) { ... mu.Unlock(); }
(and the spin loop `while (!ok) ok = mu.TryLock();`) was unresolvable:
the local-variable map discarded the merged definition of `ok`, so the
branch on it did not count as checking the result, drawing the beta
"unchecked result" warning at the very check plus a spurious release
warning inside the guarded region. The map now records such merges as
two-operand phi definitions, and the decode resolves the ones whose
value still identifies the call's result.
Design details:
[124 lines not shown]
Thread Safety Analysis: Look through elidable copies of scoped lockables
Under C++11/14, initializing a guard variable from a factory --
`MutexLock scope = lock();` with `MutexLock lock() ACQUIRE(mu)` --
loses the guard: the initializer is an elidable copy (or move)
construction from the materialized temporary the call returned, and
VisitDeclStmt does not look through it, so the scope object recorded
for the call is never bound to the variable. The CFGTemporaryDtor
element then finds the object still unclaimed and runs the guard
destructor at the end of the full-expression, releasing the underlying
capabilities immediately, and the variable's own destructor later
warns "releasing mutex 'scope' that was not held". Returning a guard by
value from an annotated factory has the same defect on the return
side: in `MutexLock lock() ACQUIRE(mu) { return MutexLock(&mu); }` the
temporary's destructor element precedes the return, so the factory
releases what it just acquired and is diagnosed for not holding `mu`
at its own end.
Fix in VisitCXXConstructExpr: an elidable copy or move construction of
[74 lines not shown]
Thread Safety Analysis: Resolve a try-acquire result behind a logical operator's value join
A `&&` or `||` was decoded only in situ, as the block's own terminator
condition, where the block evaluating the operator's right-hand side is
reached on the non-short-circuiting edge alone and the branch is exactly
a branch on the RHS. Reached any other way the descent was refused --
except that a negation above the operator (`if (!(c || mu.TryLock()))`)
was not noticed at all: the walk descended as if in situ, and the edge
the short-circuit also reaches was read as the call's result, silencing
the guarded uses on the path where the try-acquire never ran.
Decide in situ by the CFG rather than by what the walk passed through:
the operator is in situ when the innermost RHS of its chain is an element
of the decoded block. Otherwise its value was materialized at a join the
short-circuit edge also reaches, which is a merge of the RHS's result
with the LHS's constant -- true for `||`, false for `&&` -- exactly what
the ambiguous-edge mark already models for a phi: the edges where the
value may be the constant prove nothing (the call may not have executed),
the other edge proves the call ran and what it returned. That restores a
[51 lines not shown]
Thread Safety Analysis: Diagnose a try-acquire that acquires a
capability regardless of its result
The same capability listed under opposite success values of a call's
try-acquire attributes is acquired whichever way the call returns. So
far that degenerate annotation was handled by the general machinery:
the capability's second recording at the call was diagnosed like any
repeat try-acquire, and its try facts resolved to held on both edges of
a branch on the result.
Reconcile the record at the call instead (reconcileTryAcquireCaps()):
the capability moves out of the polarity sets of its TryAcquireCapsMap
entry into an unconditional group, and handleCall() turns that group
into an unconditional acquisition under a dedicated
warn_try_lock_regardless_of_result -- the capability becomes held at
the call, and no conditional try fact is left for a branch to resolve or
a failure edge to release (tryheld_regardless_of_result,
tryheld_regardless_of_result_unbranched). Every capability still
recorded then matches one polarity at a branch (a capability listed
[45 lines not shown]
Thread Safety Analysis: Diagnose a try-acquire whose result is never
checked
A conditional try fact means "held iff the try-acquire succeeded". When
the analysis loses track of one -- at a join with a path that does not
hold the capability, or at the end of the function -- the result was
never used to determine whether the acquisition happened, so on the
paths where it succeeded the capability is leaked. Such a fact was
dropped silently. Diagnose it under -Wthread-safety-beta with a new
warn_try_acquire_never_checked, noting the try-acquire call.
* Exempt: a join whose terminator rebranches on the result (the fact
is demoted and re-resolved on the outgoing edges instead); asserted
and universal capabilities, whose loss the removal warnings likewise
treat as not actionable; a guard's own conditional acquisition at an
interior join, as the lost-hold diagnostics already exempt managed
capabilities (the live scoped fact's destructor discharges it; only
the scope ending or repeating can leak it); and loop joins for now,
where a result the code checks on the paths around the loop is not
[56 lines not shown]
Thread Safety Analysis: Resolve try-acquire facts at every branch on the
result
getEdgeLockset() so far resolved a call's still-conditional try facts
only at a plain if/else branch directly on the result. Now every branch
on a try-acquire result resolves every try fact of the call -- resolved
ones as well as conditional ones -- and rebranches, compound
short-circuit conditions and switches resolve like the plain branch. In
particular this fixes the common assert-then-branch shape (promote at
the assert, branch again later), which drew "already held" plus "not
held on every path".
TryFactEntry gains the two states these resolutions leave behind:
ProvedNotHeld, the record of a failure edge, and Released, the record
that a hold a branch proved has been released since; at a join, Released
on either side is Released.
Design details:
[205 lines not shown]
Thread Safety Analysis: Fold scoped lockables into the conditional-hold model
A scoped lockable whose constructor is a try-acquire
(`std::unique_lock lock(mu, std::try_to_lock)`-style) recorded its
capabilities but created no try facts: uses under the guard warned as if
nothing was acquired, the destructor released nothing, and nothing
recorded that the capability is unheld after the scope. The
construction now creates a conditional try fact per recorded capability,
like a direct try-acquire call, with the construction as its origin.
* The try facts are Managed, and the capabilities are registered as the
scoped fact's underlying mutexes, so the destructor reaches them --
but only the capabilities whose try fact was really created:
addTryLock() reports that, so a capability it declined (already held
in the other kind, say), or one the same construction also acquires
definitely, is not the guard's to release.
The guard owns exactly the try facts its construction created
(ScopedLockableFactEntry::CondAcquireExpr), found by origin
(FactSet::removeConditionalsOf()) whether they nest over a definite
[21 lines not shown]
NAS-145217 / 28.0.0-BETA.1 / Fix snapshot task queries failing on a zero lifetime (by themylogin) (#20199)
The API accepted a lifetime of 0 for periodic snapshot tasks until
NAS-142610 added a minimum of 1 to the entry model. Rows saved with 0
before that change now fail validation on every pool.snapshottask.query
call, which breaks pool export and zettarepl. This migration raises
those rows to 1, which only keeps their snapshots longer.
Original PR: https://github.com/truenas/middleware/pull/20197
---------
Co-authored-by: themylogin <themylogin at gmail.com>
[libc][docs] Generate math.h and complex.h status tables (#241044)
Maintaining static Markdown implementation tables in
libc/docs/headers/complex.md and libc/docs/headers/math/index.md lets
documentation drift behind exported entrypoints and hides type, macro,
and POSIX coverage. Flattening these headers into single-column function
lists would discard the per-precision matrices and ULP accuracy bounds
that contributors rely on.
Add data-driven family matrix rendering to docgen using YAML-configured
precision columns, group headings, ULP accuracy badges, and Annex F/G
error-handling section links. Migrate math.h and complex.h to docgen
catalogues, move the math engineering, GPU conformance, performance, and
algorithm documentation to libc/docs/math/index.md and
libc/docs/math/log.md, filter placeholder GPU math stubs, and scan macro
headers included from .h.def templates.
Assisted-by: Automated tooling, human reviewed.
Check the register class of wide GPR operands in MIR
The assembly prints a GPR the same way whether it is used as a 32-bit or
a 64-bit register, so the old checks couldn't show the fix working. Stop
after isel and check the register class of each inline asm operand.
Also add i64 cases for "r" and "b", an i32 case, and a 32-bit PowerPC
RUN line.
Co-Authored-By: Claude Opus 5.5 <noreply at anthropic.com>
Thread Safety Analysis: Track try-acquired capabilities as try facts of their call
Track try-acquire states as regular facts, so they aren't invisible to
the analysis before they are branched on. This implements just the basic
pass, and then there are many planned follow up to make it more
permissive. The goal at each commit is to be entirely accurate (no false
negatives), but also to try to cause minimal changes without the beta
flag (which enables better detection of lost unlocks, so without which
we expect many false-negatives).
Each try-acquire fact is keyed to the call. A branch on the result
resolves each try fact against that record: on the edge where its
attribute reports success it folds into the capability's definite fact
(creating it, or deepening it one level) and stays beside it as the
proof of that level (ProvedHeld); on the other edge it is dropped.
Attributes with mixed success values thus resolve per capability.
The state of the capability in the lockset may ternary: not-held,
conditional (only conditional try facts) or held (a definite fact). Try
[68 lines not shown]
Thread Safety Analysis: Separate try-acquire facts from definite facts [NFCI]
This is preparation for the next commit, which implements the
try-acquire facts on the TryFactEntry structure introduced here. Instead
of assuming all facts are definite, replace the accessors with ones that
name what they look for.
by capability, definite findDefinite, findDefiniteIter,
findDefiniteUniv,
findDefinitePartialMatch, removeDefinite
by capability, try facts findTryFact, findTryFactIter,
firstConditional, anyConditional,
collectTryFacts, removeConditionalsOf,
removeAllConditional
by capability, either findDefiniteOrConditional (held or
possibly held)
by identity findFactIter, removeFact, removeAt,
replaceFact
for a join findCounterpart, findCounterpartIter (the
[3 lines not shown]
[clang] Relocate DWARF across sections on Mach-O firmware targets (#239797)
Change the Darwin Toolchain to pass -grelocatable-dwarf for embedded
Mach-O targets when emitting DWARF 5 or later.
Assisted-by: Claude
Depends on https://github.com/llvm/llvm-project/pull/239793
This enables workflows that involve doing incremental links that
concatenate DWARF contributions.