You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This adds a fourth node type, and a fourth edge flow, both called
"type". The idea is to represent types as first-class elements in the
graph representation. This allows greater compositionality by breaking
up composite types into subcomponents, and decreases the required
vocabulary size required to achieve a given coverage.
Background
----------
Currently, type information is stored in the "text" field of nodes for
constants and variables, e.g.:
node {
type: VARIABLE
text: "i8"
}
There are two issues with this:
* Composite types end up with long textual representations,
e.g. "struct foo { i32 a; i32 b; ... }". Since there is an
unbounded number of possible structs, this prevents 100% vocabulary
coverage on any IR with structs (or other composite types).
* In the future, we will want to encode different information on data
nodes, such as embedding literal values. Moving the type information
out of the data node "frees up" space for something else.
Overview
--------
This changes the representation to represent types as first-class
elements in the graph. A "type" node represents a type using its
"text" field, and a new "type" edge connects this type to variables or
constants of that type, e.g. a variable "int x" could be represented as:
node {
type: VARIABLE
text: "var"
}
node {
type: TYPE
text: "i32"
}
edge {
flow: TYPE
source: 1
}
Composite types
---------------
Types may be composed by connecting multiple type nodes using type
edges. This allows you to break down complex types into a graph of
primitive parts. The meaning of composite types will depend on the
IR being targetted, the remainder describes the process for
LLVM-IR.
Pointer types
-------------
A pointer is a composite of two types:
[variable] <- [pointer] <- [pointed-type]
For example:
int32_t* instance;
Would be represented as:
node {
type: TYPE
text: "i32"
}
node {
type: TYPE
text: "*"
}
node {
type: VARIABLE
text: "var"
}
edge {
text: TYPE
target: 1
}
edge {
text: TYPE
source: 1
target: 2
}
Where variables/constants of this type receive an incoming type edge
from the [pointer] node, which in turn receives an incoming type edge
from the [pointed-type] node.
One [pointer] node is generated for each unique pointer type. If a
graph contains multiple pointer types, there will be multiple
[pointer] nodes, one for each pointed type.
Struct types
------------
A struct is a compsite type where each member is a node type which
points to the parent node. Variable/constant instances of a struct
receive an incoming type edge from the root struct node. Note that
the graph of type nodes representing a composite struct type may be
cyclical, since a struct can contain a pointer of the same type (think
of a binary tree implementation).
The type edges from member nodes to the parent struct are
positional. The position indicates the element number. E.g. for a
struct with three elements, the incoming type edges to the struct node
will have positions 0, 1, and 2.
This example struct:
struct s {
int8_t a;
int8_t b;
struct s* c;
}
struct s instance;
Would be represented as:
node {
type: TYPE
text: "struct"
}
node {
type: TYPE
text: "i8"
}
node {
type: TYPE
text: "*"
}
node {
type: VARIABLE
text: "var"
}
edge {
flow: TYPE
target: 1
}
edge {
flow: TYPE
target: 1
position: 1
}
edge {
flow: TYPE
target: 2
position: 2
}
edge {
flow: TYPE
source: 2
}
edge {
flow: TYPE
target: 3
}
Array Types
-----------
An array is a composite type [variable] <- [array] <- [element-type].
For example, the array:
int a[10];
Would be represented as:
node {
type: TYPE
text: "i32"
}
node {
type: TYPE
text: "[]"
}
node {
type: VARIABLE
text: "var"
}
edge {
flow: TYPE
target: 1
}
edge {
flow: TYPE
source: 1
target: 2
}
github.com//issues/82
0 commit comments