Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
H
Hercules
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
llvm
Hercules
Merge requests
!2
Def use, dataflow, typechecking, structural verification, IR and DESIGN.md updates
Code
Review changes
Check out branch
Download
Patches
Plain diff
Merged
Def use, dataflow, typechecking, structural verification, IR and DESIGN.md updates
ir_dev
into
main
Overview
3
Commits
68
Pipelines
0
Changes
12
1 unresolved thread
Hide all comments
Merged
rarbore2
requested to merge
ir_dev
into
main
1 year ago
Overview
3
Commits
68
Pipelines
0
Changes
12
1 unresolved thread
Hide all comments
Expand
Add def use analysis, creates compact immutable def use map
Add reverse postorder and dataflow analysis - computes a generic dataflow analysis over an arbitrary lattice
Typecheck whole IR
Verify IR structure (verify projections mostly)
Add extractsum
Update DESIGN.md
0
0
Merge request reports
Compare
main
version 2
3801e703
1 year ago
version 1
7e268735
1 year ago
main (base)
and
latest version
latest version
d80d1cf9
68 commits,
1 year ago
version 2
3801e703
67 commits,
1 year ago
version 1
7e268735
66 commits,
1 year ago
12 files
+
1671
−
94
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
Files
12
Search (e.g. *.vue) (Ctrl+P)
hercules_ir/src/dataflow.rs
0 → 100644
+
126
−
0
Options
extern
crate
bitvec
;
use
dataflow
::
bitvec
::
prelude
::
*
;
use
crate
::
*
;
/*
* Trait for a type that is a semilattice. Semilattice types must also be Eq,
* so that the dataflow analysis can determine when to terminate.
*/
pub
trait
Semilattice
:
Eq
{
fn
meet
(
a
:
&
Self
,
b
:
&
Self
)
->
Self
;
fn
bottom
()
->
Self
;
fn
top
()
->
Self
;
}
/*
* Top level forward dataflow function. This routine is slightly more generic
* than the typical textbook definition. The flow function takes an ordered
* slice of predecessor lattice values, rather than a single lattice value.
* Thus, the flow function can perform non-associative and non-commutative
* operations on the "in" lattice values. This makes this routine more useful
* for some analyses, such as typechecking. To perform the typical behavior,
* the flow function should start by meeting the input lattice values into a
* single lattice value.
*/
pub
fn
forward_dataflow
<
L
,
F
>
(
function
:
&
Function
,
reverse_postorder
:
&
Vec
<
NodeID
>
,
mut
flow_function
:
F
,
)
->
Vec
<
L
>
where
L
:
Semilattice
,
F
:
FnMut
(
&
[
&
L
],
&
Node
)
->
L
,
{
// Step 1: compute NodeUses for each node in function.
let
uses
:
Vec
<
NodeUses
>
=
function
.nodes
.iter
()
.map
(|
n
|
get_uses
(
n
))
.collect
();
// Step 2: create initial set of "out" points.
let
mut
outs
:
Vec
<
L
>
=
(
0
..
function
.nodes
.len
())
.map
(|
id
|
{
flow_function
(
&
vec!
[
&
(
if
id
==
0
{
L
::
bottom
()
}
else
{
L
::
top
()
});
uses
[
id
]
.as_ref
()
.len
()],
&
function
.nodes
[
id
],
)
})
.collect
();
// Step 3: peform main dataflow loop.
loop
{
let
mut
change
=
false
;
// Iterate nodes in reverse post order.
for
node_id
in
reverse_postorder
{
// Assemble the "out" values of the predecessors of this node. This
// vector's definition is hopefully LICMed out, so that we don't do
// an allocation per node. This can't be done manually because of
// Rust's ownership rules (in particular, pred_outs holds a
// reference to a value inside outs, which is mutated below).
let
mut
pred_outs
=
vec!
[];
for
u
in
uses
[
node_id
.idx
()]
.as_ref
()
{
pred_outs
.push
(
&
outs
[
u
.idx
()]);
}
// Compute new "out" value from predecessor "out" values.
let
new_out
=
flow_function
(
&
pred_outs
[
..
],
&
function
.nodes
[
node_id
.idx
()]);
if
outs
[
node_id
.idx
()]
!=
new_out
{
change
=
true
;
}
// Update outs vector.
outs
[
node_id
.idx
()]
=
new_out
;
}
// If no lattice value changed, we've reached the maximum fixed point
// solution, and can terminate.
if
!
change
{
break
;
}
}
// Step 4: return "out" set.
outs
}
/*
* Compute reverse post order of nodes in function.
*/
pub
fn
reverse_postorder
(
def_uses
:
&
ImmutableDefUseMap
)
->
Vec
<
NodeID
>
{
// Initialize order vector and bitset for tracking which nodes have been
// visited.
let
order
=
Vec
::
with_capacity
(
def_uses
.num_nodes
());
let
visited
=
bitvec!
[
u8
,
Lsb0
;
0
;
def_uses
.num_nodes
()];
// Order and visited are threaded through arguments / return pair of
// reverse_postorder_helper for ownership reasons.
let
(
mut
order
,
_
)
=
reverse_postorder_helper
(
NodeID
::
new
(
0
),
def_uses
,
order
,
visited
);
// Reverse order in-place.
order
.reverse
();
order
}
fn
reverse_postorder_helper
(
node
:
NodeID
,
def_uses
:
&
ImmutableDefUseMap
,
mut
order
:
Vec
<
NodeID
>
,
mut
visited
:
BitVec
<
u8
,
Lsb0
>
,
)
->
(
Vec
<
NodeID
>
,
BitVec
<
u8
,
Lsb0
>
)
{
if
visited
[
node
.idx
()]
{
// If already visited, return early.
(
order
,
visited
)
}
else
{
// Set visited to true.
visited
.set
(
node
.idx
(),
true
);
// Iterate over users.
for
user
in
def_uses
.get_users
(
node
)
{
(
order
,
visited
)
=
reverse_postorder_helper
(
*
user
,
def_uses
,
order
,
visited
);
}
// After iterating users, push this node.
order
.push
(
node
);
(
order
,
visited
)
}
}
Loading