Skip to content

Counting Immutable Beans #82

Open
Open
@andorp

Description

@andorp

Implementation of the Counting Immutable Beans (CIB) for the GRIN compiler.

Summary

CIB uses instrumentation of the original program. There are four new instructions in the syntax
that are inserted via instrumentation. This can be categorized into two;

  • reference counter instructions:
    • inc
    • dec
  • heap location reuse:
    • reset
    • reuse

In the CIB approach every heap location has a reference counter associated with it. Inc increments the counter for the location, and also increments all the referred locations transitively.
Dec decrements the counter for the location, and also decrements all the referred locations transitively.

Reset, reuse:

From the CIB paper:

let y = reset x.

If x is a shared value, than y is set to a special pointer value BOX, otherwise to the heap location associated with x.
If x is not shared than reset decrements the reference counters of the components of x, and y is set to x.

let z = reuse y in ctor_i w.

If y is BOX reuse allocates a new heap for the constructor.
If y is not Box the runtime reuses the heap location for storing the constructor.

Application of the same idea for GRIN:

Differences: meanwhile Lean's IR put every variable on the heap, GRIN uses variables as were registers and only a subset of the registers are associated with heap locations. A register is associated with heap location if its type is Loc. This means the GRIN implementation of the CIB approach needs a type environment which tells which variables can be affected by the CIB operations.

In GRIN:

  • The CIB instrumentation should happen after the optimization steps.
  • Special interpreter should be implemented which handles the CIB instructions.
  • Probably it should have its own LLVM code generator and LLVM implemented runtime, preferably a plugin for the existing one.

We need to add 4 new instructions:

  • x <- reset y; where y is a heap location, x can be a special heap location, which can be BOX too.
  • z <- reuse x y; where x is a special heap location created by reset, and y is a Node value.
  • z <- inc x; where x is a heap location, it transitively increments the reference counters in the locations. Cycle detection should happen. The increment operation computes unit as its return value.
  • z <- dec x; where x is a heap location, it transitively decrements the reference counters in the locations. Cycle detection should happen. When the counter reaches zero, the runtime must deallocate the location. The decrement operation computes unit as its return value.

The GRIN nodes store primitive values, but the runtime makes the difference between location values and primitive values, thus it is able to create the transitive closure of the reachability relation of a location and manipulate its reference counters.

Every of the four instructions needs to be implemented in the GRIN runtime/interpreter.

In the original paper reuse of the constructors could happen only of the arity of the constructors
are the same. But in GRIN as the runtime needs to allocate heaps based on the type of the heap location. This means every heap location can have its own arity, and reuse if the heap location is possible only if the new node does not exceeds the arity of the heap node. Otherwise a new node needs to be allocated, with the maximum arity.

The most important change is the reuse construction. It changes certain instances of the
store operation to the reuse operation.

Before:
x <- store y;

After:
z <- reset w;
...
x <- reuse z y;

In this case we need to decide to reuse the heap location associated with w only if w can accommodate all the possible values of x. This means the max-arity(w) >= max-arity(x). Meanwhile Lean's approach uses the arity of the constructors in the alternatives, we can use the abstract information of all the possible runs.

Implementation steps:

  1. Import abstracting the definitional interpreters from the mini-grin repo
  2. Change the implementation to use base functors instead of Expr datatype
  3. Implement reference statistics with the new interpreter, as a warm-up exercise
  4. Implement CIB program instrumentation for GRIN producing ExprF :+: CibF AST
  5. Implement interpreter for CIB extended GRIN program
  6. Extra: Implement LLVM codegen plugin for CIB instructions

Metadata

Metadata

Assignees

Labels

proposalA suggestion on how to improve the compiler

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions