Skip to content

[hls-fuzzer] Add cross type system transfer functions - #1023

Open
zero9178 wants to merge 3 commits into
mainfrom
users/zero9178/wrap-transfer-fn
Open

[hls-fuzzer] Add cross type system transfer functions#1023
zero9178 wants to merge 3 commits into
mainfrom
users/zero9178/wrap-transfer-fn

Conversation

@zero9178

Copy link
Copy Markdown
Collaborator

Prior to this PR, every type system in a conjunction operated completely independent of other present type systems. This means that it was wholly responsible for context calculations based on its transfer functions.

However, some type systems are explicitly designed as "action" type systems, that restrict program generation in some interesting way and do so based on some initial value in an input context. The 'OptionalTypeSystem' is e.g. one such case that allows only applying a sub-typesystem to some subset of the program.

To enable the use case of "analysis" type systems that then cause an action in an "action" type system, this PR adds the concept of cross transfer functions.

These are special transfer functions that can be used in subclasses of 'ConjunctionTypeSystemBase' and allows creating a transfer function that depends on another type system's context when calculating another's.

Specific use-case for the future is that for a high II type system, we have one type system recognizing an innermost loop which then enables the generation of high latency reccurrences within innermost loops. This way neither type systems need to know of each other, only the conjuncting type system wires them up together.

@zero9178
zero9178 requested a review from Jiahui17 July 28, 2026 21:25
@zero9178
zero9178 force-pushed the users/zero9178/wrap-transfer-fn branch 2 times, most recently from 5e4f1da to 1e7cc19 Compare August 3, 2026 15:16
Prior to this PR, every type system in a conjunction operated completely independent of other present type systems.
This means that it was wholly responsible for context calculations based on its transfer functions.

However, some type systems are explicitly designed as "action" type systems, that restrict program generation in some interesting way and do so based on some initial value in an input context. The 'OptionalTypeSystem' is e.g. one such case that allows only applying a sub-typesystem to some subset of the program.

To enable the use case of "analysis" type systems that then cause an action in an "action" type system, this PR adds the concept of cross transfer functions.

These are special transfer functions that can be used in subclasses of 'ConjunctionTypeSystemBase' and allows creating a transfer function that depends on another type system's context when calculating another's.

Specific use-case for the future is that for a high II type system, we have one type system recognizing an innermost loop which then enables the generation of high latency reccurrences within innermost loops. This way neither type systems need to know of each other, only the conjuncting type system wires them up together.
@zero9178
zero9178 force-pushed the users/zero9178/wrap-transfer-fn branch from 94f1272 to b12cf3b Compare August 4, 2026 08:52

@Jiahui17 Jiahui17 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.

started looking at this super complicated one... some clarification questions:

Comment thread tools/hls-fuzzer/ConjunctionTypeSystem.h
/// given type systems invariants.
template <std::size_t subElement, typename SubTypeSystem,
typename... dependencies, typename TransferFns, typename F>
static void crossTransferFns(TransferFns &transferFnArray, F &&f) {

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.

Is f the one that crosses the results from different subtypesystem and does transferFnArray contain the transferFns of the subtypesystem?

If yes I suggest giving more descriptive and different names to them

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

transferFns must contain the transfer funciton of the conjunction type system (i.e. whatever is returned by Base::get*TransferFn). f is the map that implements the crossing yes

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.

could you rename f to something like "crossingFunc"?

Comment thread tools/hls-fuzzer/ConjunctionTypeSystem.h
// Self-references in dependencies are not legal in 'wrap' as the resulting
// node would depend on itself and cause a cycle!
// For that reason we filter them out here and reinsert them later.
using CalcFilter = FilterDeps<subElement, dependencies...>;

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.

what does this do?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is basically a utility struct that given a list of dependencies (i.e. Dep<TypeSystemIndex, index>) gets rid of any instances of Dep<..., subElement>.
This is needed since wrap doesn't handle self-dependencies (and shouldn't IMO). The filtered list of Deps is the Tuple below. The match function additionally tells us whether the given index originally referred to a Dep<TypeSystemIndex, index> and is used later.

I've added a comment

// Filtered 'Dep' instances without 'subElement'.
using Tuple = typename CalcFilter::value;

auto &transferFn = std::get<subElement>(transferFnArray);

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.

explain what this one is (the original transferFn before crossing?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Exactly! I've added a comment

Comment thread tools/hls-fuzzer/ConjunctionTypeSystem.h
.template wrap<Context,
std::decay_t<decltype(newDeps)>::index...>(
[f = std::forward<F>(f)](
llvm::function_ref<Context()> wrapped,

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 name wrapped is too generic here (could be something like transferFnWithCrossing

Comment on lines +469 to +473
std::get<typename SubTypeSystem::Context>(context) =
std::apply(
f,
// Finally, return the context of just the
// requested type systems.

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.

What if we need to modify the context of multiple type systems?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

One can call crossTransferFns multiple times with different target type systems without issues, I've added it to the method description.

Comment thread tools/hls-fuzzer/ConjunctionTypeSystem.h
std::forward<CrossingFunc>(crossingFunc)](
llvm::function_ref<Context()> originalTransferFn,
const auto &...deps) {
// Context prior to the crossing.

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.

Context computed by the transferFns, before crossing

llvm::function_ref<Context()> originalTransferFn,
const auto &...deps) {
// Context prior to the crossing.
Context context = originalTransferFn();

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.

context -> contextBeforeCrossing


I find it quite confusing that we need to work with both

  1. the concrete values of the context
  2. the template parameters

But it is pretty hard to tell which one is which (e.g., is a variable named context a concrete value or a type calculated from the template parameter?

Is it possible to name the variables differently to make it more explicit?

///
/// This method makes it possible for the class implementing the conjunction
/// to implement logic that modifies the input context of 'subElement'
/// of an 'ASTNode' (deduced from its transfer functions).

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.

/// to implement logic that modifies the input context (computed by the original TransferFns) of 'subElement'

/// to implement logic that modifies the input context of 'subElement'
/// of an 'ASTNode' (deduced from its transfer functions).
///
/// One call crosses exactly one sub element ('subElement') of exactly one sub

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.

One call modifies?

// First remove the 'ASTNode's from the argument list.
// This is now equal to just the context's without
// the self references.
auto contextsOnly = mapTuplesInto(

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.

for instance, here, this variable is called contextsOnly (c.f., context) but it is a tuple of templated struct type (compared to the context which is an actual value

Comment on lines +441 to +443
/// Returns an 'OpaqueTransferFn' over 'TypingContext' that runs 'f' in place
/// of 'this', handing 'this' to it so that it can run it and adjust or
/// reinterpret what it computed.

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.

What is 'this'?


Still not super sure why we need this

if constexpr (std::is_same_v<Sentinel, T>)
return std::forward_as_tuple(context);
else
return std::forward_as_tuple(context, arg);

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.

don't we need only the context values here? Why are we still forwarding Deps (typesystem + index)?

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