dart-sdk/runtime/vm/locations.h
vegorov@google.com 5402bf689d Heuristically predict interference on the back edge and use it to minimize number of register reshuffling which is especially expensive when cycles of XMM registers arise.
When allocating free register check if hint can potentially interfere on the back edge try ignoring hint and search for a better candidate.

Additionally fix handling of constants in the liveness analysis to accommodate constants used as immediates.

R=fschneider@google.com
BUG=

Review URL: https://codereview.chromium.org//11418135

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15291 260f80e4-7a28-3924-810f-c04153c831b5
2012-11-23 16:04:34 +00:00

479 lines
13 KiB
C++

// Copyright (c) 2012, 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.
#ifndef VM_LOCATIONS_H_
#define VM_LOCATIONS_H_
#include "vm/allocation.h"
#include "vm/assembler.h"
#include "vm/bitfield.h"
namespace dart {
class BufferFormatter;
class Value;
// Location objects are used to connect register allocator and code generator.
// Instruction templates used by code generator have a corresponding
// LocationSummary object which specifies expected location for every input
// and output.
// Each location is encoded as a single word: for non-constant locations
// low 3 bits denote location kind, rest is kind specific location payload
// e.g. for REGISTER kind payload is register code (value of the Register
// enumeration), constant locations contain a tagged (low 2 bits are set to 01)
// Object handle
class Location : public ValueObject {
private:
enum {
// Number of bits required to encode Kind value.
kBitsForKind = 3,
kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind,
};
static const uword kInvalidLocation = 0;
static const uword kConstantMask = 0x3;
static const intptr_t kMachineRegisterMask = 0x6;
static const intptr_t kMachineRegister = 0x6;
public:
// Constant payload can overlap with kind field so Kind values
// have to be chosen in a way that their last 2 bits are never
// the same as kConstant.
enum Kind {
// This location is invalid. Payload must be zero.
kInvalid = 0,
// Constant value. This location contains a tagged Object handle.
kConstant = 1,
// Unallocated location represents a location that is not fixed and can be
// allocated by a register allocator. Each unallocated location has
// a policy that specifies what kind of location is suitable. Payload
// contains register allocation policy.
kUnallocated = 2,
// Spill slot allocated by the register allocator. Payload contains
// a spill index.
kStackSlot = 3,
kDoubleStackSlot = 4,
// Register location represents a fixed register. Payload contains
// register code.
kRegister = 6,
// XmmRegister location represents a fixed xmm register. Payload contains
// its code.
kXmmRegister = 7,
};
Location() : value_(kInvalidLocation) {
ASSERT(IsInvalid());
}
bool IsInvalid() const {
return value_ == kInvalidLocation;
}
// Constants.
bool IsConstant() const {
ASSERT((kConstant & kConstantMask) == kConstant);
return (value_ & kConstantMask) == kConstant;
}
static Location Constant(const Object& obj) {
Location loc(reinterpret_cast<uword>(&obj) | kConstant);
ASSERT(&obj == &loc.constant());
return loc;
}
const Object& constant() const {
ASSERT(IsConstant());
return *reinterpret_cast<const Object*>(value_ & ~kConstantMask);
}
// Unallocated locations.
enum Policy {
kAny,
kPrefersRegister,
kRequiresRegister,
kRequiresXmmRegister,
kWritableRegister,
kSameAsFirstInput,
};
bool IsUnallocated() const {
return kind() == kUnallocated;
}
bool IsRegisterBeneficial() {
return !Equals(Any());
}
static Location UnallocatedLocation(Policy policy) {
return Location(kUnallocated, PolicyField::encode(policy));
}
// Any free register is suitable to replace this unallocated location.
static Location Any() {
return UnallocatedLocation(kAny);
}
static Location PrefersRegister() {
return UnallocatedLocation(kPrefersRegister);
}
static Location RequiresRegister() {
return UnallocatedLocation(kRequiresRegister);
}
static Location RequiresXmmRegister() {
return UnallocatedLocation(kRequiresXmmRegister);
}
static Location WritableRegister() {
return UnallocatedLocation(kWritableRegister);
}
// The location of the first input to the instruction will be
// used to replace this unallocated location.
static Location SameAsFirstInput() {
return UnallocatedLocation(kSameAsFirstInput);
}
// Empty location. Used if there the location should be ignored.
static Location NoLocation() {
return Location();
}
Policy policy() const {
ASSERT(IsUnallocated());
return PolicyField::decode(payload());
}
// Register locations.
static Location RegisterLocation(Register reg) {
uword payload =
RegisterField::encode(reg) |
RepresentationField::encode(kDouble); // Unused for Register.
return Location(kRegister, payload);
}
bool IsRegister() const {
return kind() == kRegister;
}
Register reg() const {
ASSERT(IsRegister());
return RegisterField::decode(payload());
}
// XMM registers and double spill slots can contain either doubles
// or 64-bit integers.
enum Representation {
kDouble,
kMint
};
Representation representation() const {
ASSERT(IsXmmRegister() || IsDoubleStackSlot());
return RepresentationField::decode(payload());
}
// XmmRegister locations.
static Location XmmRegisterLocation(XmmRegister reg, Representation rep) {
uword payload =
XmmRegisterField::encode(reg) | RepresentationField::encode(rep);
return Location(kXmmRegister, payload);
}
bool IsXmmRegister() const {
return kind() == kXmmRegister;
}
XmmRegister xmm_reg() const {
ASSERT(IsXmmRegister());
return XmmRegisterField::decode(payload());
}
static bool IsMachineRegisterKind(Kind kind) {
return (kind & kMachineRegisterMask) == kMachineRegister;
}
static Location MachineRegisterLocation(Kind kind,
intptr_t reg,
Representation rep) {
if (kind == kRegister) {
return RegisterLocation(static_cast<Register>(reg));
} else {
ASSERT(kind == kXmmRegister);
return XmmRegisterLocation(static_cast<XmmRegister>(reg), rep);
}
}
bool IsMachineRegister() const {
return IsMachineRegisterKind(kind());
}
intptr_t register_code() const {
ASSERT(IsMachineRegister());
return static_cast<intptr_t>(RegisterField::decode(payload()));
}
// Spill slots.
static Location StackSlot(intptr_t stack_index,
Representation rep = kDouble) {
ASSERT((-kStackIndexBias <= stack_index) &&
(stack_index < kStackIndexBias));
uword payload =
IndexField::encode(static_cast<uword>(kStackIndexBias + stack_index))
| RepresentationField::encode(rep);
Location loc(kStackSlot, payload);
// Ensure that sign is preserved.
ASSERT(loc.stack_index() == stack_index);
return loc;
}
bool IsStackSlot() const {
return kind() == kStackSlot;
}
static Location DoubleStackSlot(intptr_t stack_index, Representation rep) {
ASSERT((-kStackIndexBias <= stack_index) &&
(stack_index < kStackIndexBias));
uword payload =
IndexField::encode(static_cast<uword>(kStackIndexBias + stack_index))
| RepresentationField::encode(rep);
Location loc(kDoubleStackSlot, payload);
// Ensure that sign is preserved.
ASSERT(loc.stack_index() == stack_index);
return loc;
}
bool IsDoubleStackSlot() const {
return kind() == kDoubleStackSlot;
}
intptr_t stack_index() const {
ASSERT(IsStackSlot() || IsDoubleStackSlot());
// Decode stack index manually to preserve sign.
return IndexField::decode(payload()) - kStackIndexBias;
}
// Constants.
static Location RegisterOrConstant(Value* value);
static Location RegisterOrSmiConstant(Value* value);
static Location FixedRegisterOrConstant(Value* value, Register reg);
static Location FixedRegisterOrSmiConstant(Value* value, Register reg);
const char* Name() const;
void PrintTo(BufferFormatter* f) const;
void Print() const;
// Compare two locations.
bool Equals(Location other) const {
return value_ == other.value_;
}
// If current location is constant might return something that
// is not equal to any Kind.
Kind kind() const {
return KindField::decode(value_);
}
private:
explicit Location(uword value) : value_(value) { }
Location(Kind kind, uword payload)
: value_(KindField::encode(kind) | PayloadField::encode(payload)) { }
uword payload() const {
return PayloadField::decode(value_);
}
typedef BitField<Kind, 0, kBitsForKind> KindField;
typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
// Layout for kUnallocated locations payload.
typedef BitField<Policy, 0, 3> PolicyField;
// Layout for register locations payload. The representation bit is only used
// for XmmRegister and unused for Register.
static const intptr_t kBitsForRepresentation = 1;
static const intptr_t kBitsForRegister =
kBitsForPayload - kBitsForRepresentation;
typedef BitField<Representation,
0,
kBitsForRepresentation> RepresentationField;
typedef BitField<Register,
kBitsForRepresentation,
kBitsForRegister> RegisterField;
typedef BitField<XmmRegister,
kBitsForRepresentation,
kBitsForRegister> XmmRegisterField;
// Layout for stack slots. The representation bit is only used for
// DoubleStackSlot and unused for StackSlot.
static const intptr_t kBitsForIndex =
kBitsForPayload - kBitsForRepresentation;
typedef BitField<uword,
kBitsForRepresentation,
kBitsForIndex> IndexField;
static const intptr_t kStackIndexBias =
static_cast<intptr_t>(1) << (kBitsForIndex - 1);
// Location either contains kind and payload fields or a tagged handle for
// a constant locations. Values of enumeration Kind are selected in such a
// way that none of them can be interpreted as a kConstant tag.
uword value_;
};
class RegisterSet : public ValueObject {
public:
RegisterSet() : cpu_registers_(0), xmm_registers_(0) {
ASSERT(kNumberOfCpuRegisters < (kWordSize * kBitsPerByte));
ASSERT(kNumberOfXmmRegisters < (kWordSize * kBitsPerByte));
}
void Add(Location loc) {
if (loc.IsRegister()) {
cpu_registers_ |= (1 << loc.reg());
} else if (loc.IsXmmRegister()) {
xmm_registers_ |= (1 << loc.xmm_reg());
}
}
void Remove(Location loc) {
if (loc.IsRegister()) {
cpu_registers_ &= ~(1 << loc.reg());
} else if (loc.IsXmmRegister()) {
xmm_registers_ &= ~(1 << loc.xmm_reg());
}
}
bool ContainsRegister(Register reg) {
return (cpu_registers_ & (1 << reg)) != 0;
}
bool ContainsXmmRegister(XmmRegister xmm_reg) {
return (xmm_registers_ & (1 << xmm_reg)) != 0;
}
intptr_t xmm_regs_count() {
intptr_t count = 0;
for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; reg_idx++) {
if (ContainsXmmRegister(static_cast<XmmRegister>(reg_idx))) {
count++;
}
}
return count;
}
private:
intptr_t cpu_registers_;
intptr_t xmm_registers_;
DISALLOW_COPY_AND_ASSIGN(RegisterSet);
};
// Specification of locations for inputs and output.
class LocationSummary : public ZoneAllocated {
public:
enum ContainsCall {
kNoCall,
kCall,
kCallOnSlowPath
};
LocationSummary(intptr_t input_count,
intptr_t temp_count,
LocationSummary::ContainsCall contains_call);
intptr_t input_count() const {
return input_locations_.length();
}
Location in(intptr_t index) const {
return input_locations_[index];
}
Location* in_slot(intptr_t index) {
return &input_locations_[index];
}
void set_in(intptr_t index, Location loc) {
ASSERT(!always_calls() || loc.IsRegister());
input_locations_[index] = loc;
}
intptr_t temp_count() const {
return temp_locations_.length();
}
Location temp(intptr_t index) const {
return temp_locations_[index];
}
Location* temp_slot(intptr_t index) {
return &temp_locations_[index];
}
void set_temp(intptr_t index, Location loc) {
ASSERT(!always_calls() || loc.IsRegister());
temp_locations_[index] = loc;
}
Location out() const {
return output_location_;
}
Location* out_slot() {
return &output_location_;
}
void set_out(Location loc) {
ASSERT(!always_calls() || (loc.IsRegister() || loc.IsInvalid()));
output_location_ = loc;
}
BitmapBuilder* stack_bitmap() const { return stack_bitmap_; }
bool always_calls() const {
return contains_call_ == kCall;
}
bool can_call() {
return contains_call_ != kNoCall;
}
void PrintTo(BufferFormatter* f) const;
static LocationSummary* Make(intptr_t input_count,
Location out,
ContainsCall contains_call);
RegisterSet* live_registers() {
return &live_registers_;
}
private:
// TODO(vegorov): replace with ZoneArray.
GrowableArray<Location> input_locations_;
GrowableArray<Location> temp_locations_;
Location output_location_;
BitmapBuilder* stack_bitmap_;
const ContainsCall contains_call_;
RegisterSet live_registers_;
};
} // namespace dart
#endif // VM_LOCATIONS_H_