Skip to content

feature: make LambdaInstUseVisitor clobbering aware - #526

Open
johnbowen42 wants to merge 55 commits into
mainfrom
feature/bowen/clobbering-aware-use-analysis
Open

johnbowen42 wants to merge 55 commits into
mainfrom
feature/bowen/clobbering-aware-use-analysis

Conversation

@johnbowen42

@johnbowen42 johnbowen42 commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Currently if we have LLVM IR shapes like

// Assume %0 is a closure pointer
store int32 %1, %0
store int32 %2, %0
call registered_lambda(%0)

our analysis of the lambda callsite cannot automatically tell which store to trust as the definitive source of truth for the first slot of the lambda at the callsite. Fortunately, LLVM has O(N) (N is size of the function) built-in analysis called MemorySSA, which can answer, at the callsite call registered_lambda(%0), which store is definitive. In the parlance of MemorySSA, we say the instruction store int32 %2, %0 "clobbers", where clobbering basically means is the source of truth for that memory value and the callsite.

Fortunately, this LLVM IR shape is relatively exotic for lambda closure pointer. Nonetheless, we want Proteus to conservatively and correctly deal with simple cases of memory clobbering, explicitly reject complex LLVM IR shapes, and above all not trust the def-use graph traversal ordering as a source of ground truth for memory locations. This PR introduces a MemorySSA oracle model, that the def-use walk uses as a guide when analyzing instructions that write to lambda closure pointers. The oracle allows the analysis to ask, "which instruction clobbers the lambda closure pointer at a given lambda callsite??" Of course, an adversarial user can cook up examples where lambda closures pass through phi nodes, or a lambda is re-assembled piecemeal from disparate memory locations. These are all cases we currently conservatively reject, and update the clang frontend to do help users understand why.

Here are some of the edge cases where we fail to specialize
(1) What if the analysis finds that different slots in a lambda are stored from different pointers? -- fail to specialize
(2) What if we find that multiple user-defined function calls determine the value of different slots of the lambda closure -- fail to specialize
(3) What if we find multiple memcpys that copy different lambda slots from different source pointers? -- fail to specialize

Here are some cases where we do specialize
✅ the lambda closure pointer is clobbered at the callsite by a collection of stores, all from the same base ptr
✅ the lambda closure pointer is stored to multiple times, only one store clobbers
✅ the lambda closure pointer is clobbered at the callsite by a memory intrinsic
✅ the lambda closure pointer is clobbered at the callsite by a function call, which writes to the closure pointer using one of the above patterns

We try to handle all unsupported LLVM IR patterns from the Clang frontend which is also updated here. I also have added a flag to weaken the Clang frontend so that we can test that the LLVM IR analysis also knows about the bad shapes I describe above.

@johnbowen42
johnbowen42 added this pull request to stack #527 September 16, 2026 20:08
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from 37dfebc to 25cb26d Compare September 16, 2026 20:10
Base automatically changed from feature/bowen/mfem-raja-analysis-changes to main September 16, 2026 22:23
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch 2 times, most recently from e1298c3 to ad2d3ee Compare September 17, 2026 18:37
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from ad2d3ee to 976c996 Compare September 24, 2026 00:09
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from c328997 to 5091dc4 Compare October 12, 2026 19:22
johnbowen42 added a commit that referenced this pull request Oct 14, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch 2 times, most recently from c465b25 to 3a50d90 Compare October 15, 2026 02:45
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from 3a50d90 to 34051bc Compare October 15, 2026 17:27
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from d2b9335 to fd0f564 Compare October 15, 2026 20:11
@johnbowen42
johnbowen42 marked this pull request as draft October 15, 2026 21:47
@johnbowen42

Copy link
Copy Markdown
Collaborator Author

marking as draft temporarily while I push up several commits

@johnbowen42
johnbowen42 marked this pull request as ready for review October 16, 2026 16:05
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from 637be03 to a1de26b Compare October 26, 2026 16:43
johnbowen42 and others added 26 commits October 26, 2026 09:51
lambda_interior_slot_overwrite re-stores a two-slot functor's first slot
from the authoritative source and overwrites the second slot from a donor
functor before the call. The analysis anchors its reconciliation query at
the narrow slot-0 store, so the slot-1 write is invisible: it does not
cover the tracked byte (candidate collection skips its GEP) and does not
alias the 4-byte anchor once SROA gives both stores one provable base. The
analysis concludes the whole functor is authoritative from Initial and
specializes; slot 1 executes with Donor's value, so both FileCheck
assertions fail (a LambdaSpec line appears against CHECK-NOT, and Y prints
757 instead of 999).

This FAILS until functor-extent tracking lands (gate item 8 in
docs/dev/reviews/clobbering-aware-use-analysis.md): the query and candidate
coverage must reason about [offset, offset + sizeof(functor)), not byte 0.
Note the optnone variant of this shape declines only by accident -- spill
reloads give the two slot stores unrelatable bases, so AA conservatively
aliases the anchor -- which is the anchor-luck failure mode the review
describes.
…ysis

The wrapper operator's proteus.wrapper_call annotation gains a second
payload: sizeof the registered closure, folded per-target by Sema at
template instantiation, immune to IR type erasure. Both compilations parse
it and stamp proteus.functor_size metadata on the wrapper operator; on the
host, attachFunctorSizeToCallsiteMetadata recomputes the size from the
registered functor type, so setU64FunctionMetadata's conflict fatal doubles
as a host/device layout cross-check. The device manifest requires the
metadata and passes the extent to analyzeLambdaUses.
Three size-based checks, each pinned by a test, none touching witness
resolution: (a) the fallback MemorySSA query location is bounded to the
prefix [0, tracked offset + size), so writes past the functor (envelope
suffixes, enclosure trailing captures) can no longer be selected as the
clobber and spuriously decline correct shapes; (b) a transfer that covers
the tracked byte must cover the functor's full extent or decline, in both
visitors -- a shorter copy (the classic wrong-sizeof bug, legal C++ with no
casts) splices two sources into one functor and the byte-0 witness would
lie for the uncovered slots; (c) memset declines on any overlap with the
extent instead of ignoring interior-only hits.

The precise zero-remaining-GEP location is deliberately NOT widened to the
extent: interior slot stores are legitimate parallel copies in slot-wise
assembly (the mfem shape), and extent-wide visibility requires per-piece
reconciliation to accept them. Interior-store soundness is a frontend
contract; see gate 8 in docs/dev/reviews/clobbering-aware-use-analysis.md.

Verified via the pseudo-GPU harness on LLVM 19: all 16 lambda suites
decision-identical to the pre-change baseline, and lambda_size_test's
envelope-suffix case flips from spurious decline to specialize.
lambda_size_test pins the two extent behaviors: the enclosure shape (slot-wise assembly with a trailing capture past the functor) must specialize, and the envelope-suffix shape must specialize rather than spuriously decline when zero-index GEPs fold at -O1 and the suffix store would otherwise be selected as the clobber. The review doc records the resolved gate-8 design and the remaining frontend-diagnostic work item.
Records the open design decision underlying the interior-slot/mfem tension:
specialization needs every registered slot's reaching definition to trace to
one kernel argument, but the analysis resolves a single witness chain, so a
provenance horizon must be chosen -- assume parallel copies behind a frontend
contract (A, current), prove a common source within the assembling frame (B,
loses mfem/RAJA whose pieces arrive SROA-decomposed), or merge per-piece
kernel-arg resolutions (C, complete but N backward walks per callsite).
Pins the decision drivers, the current position, and every artifact that
must change if the position changes. Adds a Design Decisions section to the
developer manual nav.
The kernel-arg merge (C) re-proves what A assumes rather than accepting
anything new: mfem already specializes under the witness model, and the
shapes C would newly reject -- closures dissected and reassembled from
different kernel arguments through type erasure -- are written by no
portability layer, forbidden by the usage contract, and visible to the AST
checker, which is the cheaper and sharper enforcement point. Records the
PR-level framing: the value of this work is the change in failure category
(miscompile -> conservative decline/frontend error), not new acceptance.
Records the target IR shape (partial closure writes tracing to different
kernel arguments past an accepting byte-0 witness), why conforming C++
cannot emit it (closure storage is writable only through whole-object
special members; field-granular heterogeneity requires naming interior
bytes, which requires type erasure), and the two probes: the union pun --
the only cast-free storage aliasing -- declines in both variants (MemoryPhi
on the conditional path, unresolvable candidate set on the unconditional
one) and is structurally whole-object either way; the aggregate-of-closures
member splice correctly specializes, confirming the analysis keys on the
closure, not its container. Fixes the AST diagnostic's scope as the exact
erasure residue.
tests/gpu/lambda-spec-groundtruth.json records per-test
specialize/decline decisions parsed from the ProteusPass debug trace;
tools/lambda-spec-ci/lambda_spec_ci.py captures, checks, and renders it.
The trace lines are identical for ROCm and pseudo-GPU runs, so one truth
file serves both; CI can fail on any decision drift. Initial capture is
from the pseudo-GPU pipeline and is marked as requiring ROCm re-capture
before being treated as hardware ground truth.
One source base is not sufficient for multi-store reconciliation: a
field-swapping copy from a single source (dest slot 0 <- src slot 1, dest
slot 1 <- src slot 0) passed the same-base check and specialized transposed
slots. Each candidate's (source offset - destination offset) must now equal
the selected clobber's delta; mismatches decline.

Verified with the lambda-spec ground-truth checker: zero decision drift
across all 38 lambda GPU tests (pseudo-GPU pipeline, LLVM 19).
Three diagnostics implement the frontend soundness boundary decided in
docs/dev/design/lambda-closure-provenance.md -- the IR analysis's witness
model assumes closures are written only as whole objects, and these are
exactly the type-erasure constructs that can break that assumption:

- reinterpreting storage that contains a registered wrapper (directly or
  nested by value) through a type-erased mutable pointer; const reads stay
  legal.
- memcpy/memmove/memset builtins whose destination is wrapper-containing
  storage (the wrong-sizeof partial copy needs no casts; the IR guards
  decline the shapes they can see, the frontend rejects them all).
- unions with a wrapper-containing member.

lambda_interior_slot_overwrite is retired from the GPU suite: its shape is
now a compile error, covered by tests/ast/lambda_wrapper_storage_invalid.cpp
together with partial-memcpy, envelope-memset, const-read-allowed, and
union-pun cases. Ground truth updated (37 tests); spec-CI clean; all six
existing AST tests and the mfem/factory/size-test GPU positives show no new
diagnostics.
Removes code orphaned by the clobbering redesign, none of it referenced
anywhere in the tree: the reaching-pointer-stores family and
getCallBaseIdentityArgOperand/getRetInst in KernelArgVisitor.h (superseded
by the MemorySSA oracle), and needsDefUseAnalysis, the DominatorTree
member, isSelectedClobber with its commented-out call, the write-only
StoreInstToOffsetBasePtrMap, and the std::variant sketch in
KernelArgPtrUseVisitor.h. getReturnInstructions in PointerClobberAnalysis.h
becomes inline (non-inline definition in a header; ODR hazard on a second
include site).

Verified: both plugins build on LLVM 19 and 22; lambda-spec ground-truth
check reports zero decision drift across all 37 tests.
…offset

The paired AnalysisFailed/AnalysisSuccess writes (47 sites across both
visitors) collapse into a fail() helper, making the never-both-true
invariant structural; several sites that set only the failure flag now
clear the success flag too. The ptr-use visitor's visitor-global Offset
was write-only after the range refactor -- its one consumer was the
CallBase candidate's OffsetOfWriteToBasePtr, which the resolution path
never reads for calls (a selected call resumes interprocedural traversal)
-- so the member, its GEP accumulation, and the unused back() helper are
gone. offsetValueMapFailure is renamed rangeMapFailure to match the
ValueRangeMap it actually reports on.

Verified: both plugins build (LLVM 19); lambda-spec ground truth reports
zero decision drift across 37 tests; the AST rejection suite passes.
The decision-drift checker, ground-truth JSON, and its doc ship with the
verification-tooling PR (feature/bowen/pseudo-gpu-harness) so reviewers of
that small PR get the whole apparatus, and this branch's PR consumes it
once landed. The branch-tip decision capture will be re-established from a
ROCm run as part of final validation.
Its durable content lives on: the resolved design in
docs/dev/design/lambda-closure-provenance.md, the behavioral baseline in
the spec-CI ground truth (tooling branch), and the fixes themselves in
history. The finding-by-finding ledger was a working document for the
review cycle, now stale.
…n mode

The first ROCm run of the contract diagnostics rejected the analysis
suite's own provenance tests: the checks were type-level
overapproximations. Narrowed to what the design contract actually forbids:

- memcpy/memmove: diagnose only writes that PARTIALLY overlap the wrapper's
  byte interval (computed from the destination expression's member chain
  and record layout) or whose dynamic length cannot be proven to miss it.
  Whole-wrapper copies and non-overlapping prefix/suffix writes are the
  whole-object discipline itself and stay legal. memset stays strict on
  any overlap.
- reinterpret_cast: recording the cast is no longer the error; only a WRITE
  through the erased pointer (directly or via a variable initialized from
  it) is diagnosed, scanned post-traversal. container_of-style address math
  and const reads stay legal.

New plugin arg -contract-warn downgrades the contract diagnostics to
warnings; the Proteus test tree passes it so adversarial tests that
deliberately violate the contract can keep pinning the IR analysis's
conservative declines, while consumer builds via add_proteus() keep hard
errors. The AST rejection test gains positive cases for every legal form.

Verified: wrapper-storage AST test passes strict; all six prior AST tests
pass; the full GPU lambda suite compiles with zero contract errors under
-contract-warn.
@johnbowen42
johnbowen42 force-pushed the feature/bowen/clobbering-aware-use-analysis branch from a1de26b to 90b339f Compare October 26, 2026 17:34
johnbowen42 and others added 2 commits October 26, 2026 14:23
Each test asserts the correct outcome and currently fails on the
clobbering-aware analysis branch. Verified by running the device-side
compile of each file through libProteusPass (LLVM 19, gfx90a, no ROCm)
and reading the lambda manifest:

- lambda_pointee_overwrite: a helper memcpy's over the closure it
  received by pointer and invokes it directly on the argument. The
  direct-argument clobber guard only runs when a StoreInst writes the
  argument, so the manifest records kernel argument 0 (Initial) while
  the device executes Replacement.

- lambda_displaced_helper_memcpy: the closure sits at offset 4 in an
  envelope and a helper overwrites it through a field pointer. The
  transfer offset correction is frame-relative, so the manifest records
  kernel argument 1 at offset 4 instead of 0 and would fold Body.Y and
  Spare.X as the two slots.

- lambda_callee_join_no_phi: a helper memcpy's the closure, then
  branches on an unrelated value with register-only arms. The oracle
  reports live-on-entry for the multi-predecessor return block that
  has no MemoryPhi and the analysis declines; the straight-line twin
  specializes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@davidbeckingsale davidbeckingsale left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went through the full diff and spent some time running the pass offline against device IR for the shapes I was unsure about (libProteusPass built from this branch with LLVM 19, HIP device-only compile for gfx90a, reading the lambda manifest). Overall the design holds together well: the forward walk only collects candidates and acceptance requires MemorySSA's own selection to be among them, so most mistakes degrade to a decline. The findings below are the places where that does not hold, plus a few smaller things.

I pushed three regression tests to this branch (fe9f34d) that pin the confirmed issues. They assert the correct behavior, so they fail today and CI will go red until the fixes land; I verified each one reproduces by compiling its device side through the pass and reading the manifest, but I have not run them on a GPU.

Confirmed (reproduced against the built pass)

  1. Direct-argument clobber guard is bypassed by any write that is not a bare StoreInst (miscompile, lambda_pointee_overwrite).
  2. memcpy offset correction is frame-relative, so a displaced destination in a callee resolves to the wrong byte (miscompile, lambda_displaced_helper_memcpy).
  3. Oracle reports live-on-entry for a multi-predecessor block with no MemoryPhi, declining straight-line memory histories through branchy callees (spurious decline, lambda_callee_join_no_phi).

Not reproduced, from reading
4. One MemorySSA oracle per callsite.
5. Virtual bases crash getWrapperIntervalInType.
6. The erased-write diagnostic only sees reinterpret_cast.
7. LambdaArgVisitor::visitMemIntrinsic is unreachable.
8. Comments cite a review doc that is not in the tree; one test comment is stale.
9. The CUDA integration script reverts main's absolute miniforge prefix.

Details inline. Happy to pair on 1 and 2 if useful; the offline harness makes the loop a couple of minutes.

return StoreBase == &A && StoreSize &&
rangesOverlap(StoreOffset, *StoreSize, 0, FunctorSize);
});
if (MemoryAnalysisPtrUse == LambdaCB && LambdaCB->getArgOperand(0) == &A &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MemorySSA query here only runs when HasDirectPriorStore finds a same-block StoreInst whose pointer operand is the argument itself. Any other write skips it: a memcpy, a constructor or helper call that writes through the argument, a store through a GEP of the argument, a store in a dominating block, or any write at all when an addrspacecast sits between the argument and the call (that path passes &ASC as the boundary, so MemoryAnalysisPtrUse == LambdaCB is false). The walk then falls through to the caller and accepts the original object.

Reproduced with tests/gpu/lambda_pointee_overwrite.cpp: a helper does __builtin_memcpy(Target, Replacement, sizeof(F)); (*Target)();. The manifest records kernel arg 0 (Initial) while the device executes Replacement. The whole-object memcpy is legal under the new checker contract, so the frontend does not catch it either.

I see the pre-filter came in with "Fix cuda unit test", which suggests the unfiltered query produced spurious declines (probably unrelated calls before the lambda call showing up as clobbers on a non-alloca location). I think the query needs to run unconditionally on this shape, with the non-aliasing-call case handled the way callCannotModifyTrackedLocal does for allocas, rather than being gated on a syntactic store.

// source bases, rather than the source's absolute offset. For example,
// copying a field at byte 8 into a field at byte 24 needs a correction of
// 16, so the caller turns 24 into 8.
int64_t OffsetCorrection = DstOff - SrcOff;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OffsetCorrection = DstOff - SrcOff is computed from GetPointerBaseWithConstantOffset on the raw destination, which is relative to the current frame's base (the formal, in a callee). The store path at line 1153 derives its correction relative to the visitor root instead: ValueRangeMap[TrackedBase].Offset - StoreRange.Offset. When a transfer is resolved in a callee whose formal was passed a displaced pointer (&env.Body), the two disagree by that displacement.

Reproduced with tests/gpu/lambda_displaced_helper_memcpy.cpp: closure at offset 4 of an envelope, helper memcpy's over it through a field pointer. The pass log shows the callee memcpy resolving with offset-correction=0, and the manifest records kernel arg 1 at offset 4 instead of 0. With a 16-byte Pair source that stays in bounds and would fold Body.Y and Spare.X as the two slots. With an 8-byte source the same error happens to trip the full-extent check and declines, which is probably why nothing in the existing suite caught it.

Using the same root-relative displacement as the store path, (ValueRangeMap[TrackedBase].Offset - Range.Offset) - SrcOff, gives the right answer in both the root frame and callees; DstOff should drop out.

return MSSA.getLiveOnEntryDef();
if (BasicBlock *Pred = BB->getSinglePredecessor())
return getStateBefore(MSSA, *Pred->getTerminator(), VisitedBlocks);
return MSSA.getLiveOnEntryDef();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the boundary block has no prior MemoryDef, no MemoryPhi, and more than one predecessor, this returns live-on-entry. The absence of a MemoryPhi means every predecessor carries the same reaching access, so the walk should continue through the immediate dominator (or any predecessor) rather than give up. This matters because every deferred callee resolution queries at the callee's ReturnInst, which has no memory access of its own.

Reproduced with tests/gpu/lambda_callee_join_no_phi.cpp: a helper memcpy's the closure, then if (Flag) V = pureScale(Flag); with pureScale marked const, then returns V. The return block has two predecessors and an SSA phi but no MemoryPhi; the analysis logs "MemorySSA did not identify a clobbering instruction" and declines. The straight-line twin specializes. At -O2 any helper with a register-only diamond before its return hits this.

DEBUG(Logger::logs("proteus-pass") << "Beginning analysis " << "\n");
for (auto *FunctorCB : CBToAnalyze) {
LambdaArgVisitor Visitor(FunctorCB, M);
LambdaArgVisitor Visitor(FunctorCB, M, FunctorStructSize);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

analyzeLambdaUses builds a new LambdaArgVisitor per callsite and the constructor (line 227) makes a fresh MemorySSAClobberOracle, so DominatorTree, AssumptionCache, AAResults and MemorySSA are rebuilt for the same enclosing functions once per callsite, and again per functor operator in emitLambdaDeviceCallsiteManifest. The IR is not mutated during analysis, so one oracle could be shared across both loops.

const auto *BaseRecord = getCanonicalRecord(Base.getType());
uint64_t BaseOff =
Layout
.getBaseClassOffset(llvm::cast<clang::CXXRecordDecl>(BaseRecord))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Record->bases() includes virtual bases, and ASTRecordLayout::getBaseClassOffset requires a direct non-virtual base (it asserts in debug builds and reads a missing map entry otherwise). A struct Derived : virtual Base where Base holds a wrapper, memcpy'd as a whole, would hit this. Checking Base.isVirtual() and either using getVBaseClassOffset or skipping conservatively would close it.

TypeErasedWrapperStorage(TypeErasedWrapperStorage),
MemoryBuiltinOnWrapper(MemoryBuiltinOnWrapper), Reported(Reported) {}

bool VisitCXXReinterpretCastExpr(clang::CXXReinterpretCastExpr *Cast) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The erased-write diagnostic records only CXXReinterpretCastExpr and only diagnoses BinaryOperator assignments. auto *W = (uint32_t *)&Copy; W[1] = 5; compiles clean, as do static_cast<void*> chains, ++W[1], and passing the erased pointer to a function that writes through it. The IR analysis does still decline these shapes (I checked the C-style cast case), so this is diagnostic coverage rather than soundness, but the design doc leans on the checker as the contract boundary, so worth tightening or documenting.

@@ -520,7 +459,7 @@ class LambdaArgVisitor : public InstVisitor<LambdaArgVisitor> {
auto *MT = dyn_cast<MemTransferInst>(&I); // memcpy/memmove
if (!MT) {
// memset doesn't preserve any src->dst relationship we can use

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this visitor is unreachable: LambdaArgVisitor only ever pushes SSA values (store value operands, memcpy raw sources, call operands, pointer operands), never a void-typed intrinsic, so visitMemIntrinsic and visitIntrinsicInst here cannot execute and the FunctorSize coverage check added in this PR is dead. The real check is the one in LambdaInstUseVisitor::visitMemIntrinsic. Suggest deleting these or asserting unreachable so there is one source of truth.

/// Record the registered functor's byte size on each wrapper operator so
/// the kernel-arg analysis can reason about the functor's full extent
/// rather than a single byte (see gate item 8 in
/// docs/dev/reviews/clobbering-aware-use-analysis.md).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and KernelArgPtrUseVisitor.h:1010 and the design doc point readers to docs/dev/reviews/clobbering-aware-use-analysis.md and "gate 8", but no docs/dev/reviews directory exists on the branch. Either add the doc or inline the rationale. Relatedly, tests/gpu/lambda_size_test.cpp:27 still says the envelope case is EXPECTED TO FAIL while its CHECK lines require success.


# Install Clang/LLVM through conda.
install_miniforge "${PWD}/miniforge3"
install_miniforge miniforge3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes install_miniforge back to the relative miniforge3, undoing the ${PWD}/miniforge3 absolute prefix that #549 introduced and #554 kept. If that was deliberate (the commit says "Try to fix cuda integration tests"), a note on why would help; otherwise it looks like a rebase artifact.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants