28d7984e31
Issue: https://github.com/dart-lang/sdk/issues/61635 Change-Id: I7476ec7e66edd958c66e31dabcd6ab8d818594e5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509640 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
170 lines
4.5 KiB
Dart
170 lines
4.5 KiB
Dart
// 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/constant_value.dart' show ConstantValue;
|
|
import 'package:cfg/ir/instructions.dart' show MoveOp;
|
|
|
|
/// A generic operand of a machine instruction.
|
|
abstract interface class Operand;
|
|
|
|
/// Kind of physical register.
|
|
enum RegisterClass {
|
|
/// General-purpose registers.
|
|
cpu,
|
|
|
|
/// Floating-point / SIMD registers.
|
|
fpu,
|
|
}
|
|
|
|
/// Register allocation constraint for one input/output/temporary
|
|
/// location used by an IR instruction.
|
|
abstract interface class Constraint {
|
|
RegisterClass get registerClass;
|
|
}
|
|
|
|
/// Location of an IR instruction input, output or temporary.
|
|
abstract interface class Location {
|
|
Location get physicalLocation;
|
|
}
|
|
|
|
abstract base class PhysicalRegister implements Constraint, Location, Operand {
|
|
const PhysicalRegister();
|
|
int get index;
|
|
|
|
@override
|
|
Location get physicalLocation => this;
|
|
}
|
|
|
|
/// General-purpose register.
|
|
final class const Register(final int index, final String name)
|
|
extends PhysicalRegister {
|
|
@override
|
|
RegisterClass get registerClass => RegisterClass.cpu;
|
|
|
|
@override
|
|
String toString() => name;
|
|
}
|
|
|
|
const Register invalidReg = Register(-1, 'INVALID');
|
|
|
|
/// Floating-point register.
|
|
final class const FPRegister(final int index, final String name)
|
|
extends PhysicalRegister {
|
|
@override
|
|
RegisterClass get registerClass => RegisterClass.fpu;
|
|
|
|
@override
|
|
String toString() => name;
|
|
}
|
|
|
|
const FPRegister invalidFPReg = FPRegister(-1, 'INVALID');
|
|
|
|
/// Base class for all stack locations.
|
|
sealed class const StackLocation() implements Location {
|
|
@override
|
|
Location get physicalLocation => this;
|
|
}
|
|
|
|
/// Spill slot.
|
|
final class SpillSlot extends StackLocation {
|
|
/// Index of the spill slot (0, 1, ...).
|
|
final int index;
|
|
|
|
const SpillSlot(this.index);
|
|
|
|
@override
|
|
String toString() => 'stack[$index]';
|
|
}
|
|
|
|
/// Constraint and location for the parameter passed on the stack.
|
|
final class ParameterStackLocation extends StackLocation implements Constraint {
|
|
/// Parameter index (0, 1, ..., function.numberOfParameters-1).
|
|
final int paramIndex;
|
|
|
|
@override
|
|
final RegisterClass registerClass;
|
|
|
|
const ParameterStackLocation(this.paramIndex, this.registerClass);
|
|
|
|
@override
|
|
String toString() => 'param[$paramIndex]';
|
|
}
|
|
|
|
/// Location which can be allocated by register allocator.
|
|
final class VirtualLocation implements Location {
|
|
/// Physical location.
|
|
Location? location;
|
|
|
|
@override
|
|
Location get physicalLocation => location!;
|
|
|
|
@override
|
|
String toString() => 'vloc${location != null ? ':$location' : ''}';
|
|
}
|
|
|
|
extension type const OperandId._(int _raw) {
|
|
static const int instructionIdMask = 0xffffffff;
|
|
static const int operandIdexShift = 32;
|
|
|
|
OperandId.result(int instructionId) : _raw = instructionId;
|
|
OperandId.input(int instructionId, int inputIndex)
|
|
: _raw = instructionId | ((inputIndex + 1) << operandIdexShift);
|
|
OperandId.temp(int instructionId, int tempIndex)
|
|
: _raw = instructionId | ((-tempIndex - 1) << operandIdexShift);
|
|
|
|
int get instructionId => _raw & instructionIdMask;
|
|
int get operandIndex => _raw >> operandIdexShift;
|
|
|
|
bool get isResult => operandIndex == 0;
|
|
bool get isInput => operandIndex > 0;
|
|
bool get isTemp => operandIndex < 0;
|
|
|
|
int get inputIndex {
|
|
assert(isInput);
|
|
return operandIndex - 1;
|
|
}
|
|
|
|
int get tempIndex {
|
|
assert(isTemp);
|
|
return -operandIndex - 1;
|
|
}
|
|
}
|
|
|
|
/// Locations of instruction inputs, result and
|
|
/// temporaries needed to generate code for the instruction.
|
|
///
|
|
/// TODO: encode locations as int/Uint32List.
|
|
class Locations {
|
|
Location? result;
|
|
List<Location?> inputs;
|
|
List<Location?> temps;
|
|
|
|
Locations(int numInputs, int numTemps)
|
|
: inputs = List<Location?>.filled(numInputs, null),
|
|
temps = List<Location?>.filled(numTemps, null);
|
|
|
|
void setOperandLocation(OperandId operandId, Location loc) {
|
|
if (operandId.isResult) {
|
|
result = loc;
|
|
} else if (operandId.isInput) {
|
|
inputs[operandId.inputIndex] = loc;
|
|
} else {
|
|
temps[operandId.tempIndex] = loc;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Location->location move, part of ParallelMove instruction.
|
|
final class Move(var Location from, var Location to) extends MoveOp {
|
|
@override
|
|
String toString() => '$from -> $to';
|
|
}
|
|
|
|
/// Constant->location move, part of ParallelMove instruction.
|
|
final class LoadConstant(var ConstantValue value, var Location to)
|
|
extends MoveOp {
|
|
@override
|
|
String toString() => '$value -> $to';
|
|
}
|