-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cycles are problematic in TreeBuilder V2 #293
Comments
I've closed my PR for this issue as it was incomplete and a mess. @tyroguru and I discussed a multi-stage approach for making progress on this.
The ProblemThe previous steps hid the symptoms of the problem (failed compilation) but solving the problem properly requires a better understanding. Here we will look at exactly the generated code for an example data structure and why this code can't compile, then develop the solution. The type in question will be this: template <typename T>
struct LinkedListNode {
~LinkedListNode();
T head;
LinkedListNode<T>* tail = nullptr;
}; If we understand this type, which contains a cycle, as a container, we generate code such as the following: template <typename Ctx, typename T>
struct TypeHandler<LinkedListNode<T0>> {
using type = types::st::List<DB,
TypeHandler<Ctx, T0>::type
>;
...
}; This works fine. We have converted the cycle into a struct LinkedListNode_0 {
int head_0;
LinkedListNode_0* tail_1;
};
template <typename Ctx>
struct TypeHandler<LinkedListNode_0> {
using type = types::st::Pair<DB,
TypeHandler<Ctx, int>::type,
TypeHandler<Ctx, LinkedListNode_0*>::type
>;
...
}; The Static Types: Hiding the cycleTo maintain the templated static type system, which otherwise works very well, we must make this cycle disappear. Fortunately, because we are a code generator, this can be achieved by evaluating this cycle at generation time rather than compile time. Given that we have already identified, stubbed, and tested the code for identifying cycles in Steps 1 & 2 this shouldn't be too bad... We must create a Type that has the same representation in C++ as the real type but is a different type such that we can break the cycle. This is very similar to the The steps here are pretty simple:
This may seem like it's doing nothing different: the generated C++ code still has full knowledge of the cycle. But simply allowing a type to be created solves the cycles. The final codegen for our cyclic type might look something like this: struct LinkedListNode_0 {
int head_0;
CycleBreaker_1* tail_1;
};
struct CycleBreaker_1 : public LinkedListNode_0 {};
template <typename Ctx>
struct TypeHandler<Ctx, CycleBreaker_1> {
using DB = typename Ctx::DataBuffer;
struct type {
type(DB buf) : buf_{buf} {}
DB buf_;
};
void getSizeType(const CycleBreaker_1& cb, typename TypeHandler<Ctx, CycleBreaker_1>::type ty) {
return getSizeType<Ctx>(ty.buf_, static_cast<const LinkedListNode_0&>(cb));
}
}; This should basically work (with the caveat that I haven't even close to tested it). The bits left to the reader's imagination are picking the right point in the cycle to break it, and whether this usage can cover all cases. The Dynamic Types: Allow cyclesDynamic Types, on the other hand, have no problem representing cycles. However the default method of constructing them directly from the static representation won't work because the static representation would have cycles (not allowed). We can follow on from the previous generated code to make this work quite easily by modifying the type in the struct type {
static constexpr types::dy::Dynamic describe = TypeHandler<Ctx, LinkedListNode_0>::type::describe;
type(DB buf) : buf_{buf} {}
DB buf_;
}; The reason this should work is TreeBuilder Instructions: Allow cyclesTreeBuilder instructions consist of fields and processors which are also all defined at compile time. It seems that we can cheat slightly here by using a template <typename Ctx>
struct TypeHandler<Ctx, CycleBreaker_1> {
...
static constexpr auto& fields = TypeHandler<Ctx, LinkedListNode_0>::fields;
static constexpr auto& processors = TypeHandler<Ctx, LinkedListNode_0>::processors;
}; This should result in fully fixed cycles in TreeBuilder-v2. |
The method for statically typing traversal functions in the generated code cannot handle cycles. This means that we must operate on the graph before generating code to hide these cycles from the static type. Without this any type cycles such as:
Will fail at compilation of the JIT code.
The text was updated successfully, but these errors were encountered: