blob: 407528085fd4128c0d46d818e8e76ea404013a81 [file] [log] [blame]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:cfg/ir/flow_graph.dart';
import 'package:cfg/ir/instructions.dart';
import 'package:cfg/utils/arena.dart';
/// A single use of the result of the instruction in another instruction.
extension type const Use(ArenaPointer _ptr) {
// Terminator in the use lists.
static const Use Null = Use(ArenaPointer.Null);
// Each use occupies 4 slots:
// instruction index, definition index, next use, previous use.
static const int instructionOffset = 0;
static const int definitionOffset = 1;
static const int nextOffset = 2;
static const int previousOffset = 3;
// Size of each use. Should be a power of 2 for efficiency.
static const int useSize = 4;
@pragma("vm:prefer-inline")
void init(FlowGraph graph, Instruction instr) {
setInstruction(graph, instr);
setNext(graph, Use.Null);
setPrevious(graph, Use.Null);
}
@pragma("vm:prefer-inline")
Instruction getInstruction(FlowGraph graph) =>
graph.instructions[graph[_ptr + instructionOffset]];
@pragma("vm:prefer-inline")
void setInstruction(FlowGraph graph, Instruction value) {
graph[_ptr + instructionOffset] = value.id;
}
@pragma("vm:prefer-inline")
Definition getDefinition(FlowGraph graph) =>
graph.instructions[graph[_ptr + definitionOffset]] as Definition;
@pragma("vm:prefer-inline")
void setDefinition(FlowGraph graph, Definition value) {
graph[_ptr + definitionOffset] = value.id;
}
@pragma("vm:prefer-inline")
Use getNext(FlowGraph graph) => Use(ArenaPointer(graph[_ptr + nextOffset]));
@pragma("vm:prefer-inline")
void setNext(FlowGraph graph, Use value) {
graph[_ptr + nextOffset] = value._ptr.toInt();
}
@pragma("vm:prefer-inline")
Use getPrevious(FlowGraph graph) =>
Use(ArenaPointer(graph[_ptr + previousOffset]));
@pragma("vm:prefer-inline")
void setPrevious(FlowGraph graph, Use value) {
graph[_ptr + previousOffset] = value._ptr.toInt();
}
}
/// Fixed-size array of uses.
extension type const UsesArray(ArenaPointer _ptr) {
// Array has a length, followed by elements.
static const int lengthOffset = 0;
static const int elementsOffset = 1;
int getLength(FlowGraph graph) {
assert(_ptr != ArenaPointer.Null);
return graph[_ptr + lengthOffset];
}
Use at(FlowGraph graph, int index) {
assert(_ptr != ArenaPointer.Null);
assert(0 <= index && index < getLength(graph));
return Use(_ptr + elementsOffset + index * Use.useSize);
}
void truncateTo(FlowGraph graph, int newLength) {
assert(_ptr != ArenaPointer.Null);
assert((0 <= newLength) && (newLength <= getLength(graph)));
graph[_ptr + lengthOffset] = newLength;
}
static UsesArray allocate(FlowGraph graph, int length) {
assert(length >= 0);
final ptr = graph.allocate(elementsOffset + length * Use.useSize);
graph[ptr + lengthOffset] = length;
return UsesArray(ptr);
}
}
class _UsesIterator implements Iterator<Use> {
final FlowGraph graph;
Use _current = Use.Null;
Use _next;
_UsesIterator(this.graph, this._next);
@override
bool moveNext() {
_current = _next;
_next = (_current != Use.Null) ? _current.getNext(graph) : Use.Null;
return (_current != Use.Null);
}
@override
Use get current => _current;
}
class UsesIterable extends Iterable<Use> {
final FlowGraph graph;
Use _first;
UsesIterable(this.graph, this._first);
UsesIterable.empty(this.graph) : _first = Use.Null;
@override
Iterator<Use> get iterator => _UsesIterator(graph, _first);
}