summaryrefslogtreecommitdiffstats
path: root/compiler/dex/reg_storage.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/reg_storage.h')
-rw-r--r--compiler/dex/reg_storage.h259
1 files changed, 189 insertions, 70 deletions
diff --git a/compiler/dex/reg_storage.h b/compiler/dex/reg_storage.h
index 11bec99585..df5aa7b5ce 100644
--- a/compiler/dex/reg_storage.h
+++ b/compiler/dex/reg_storage.h
@@ -21,77 +21,105 @@
namespace art {
/*
- * Representation of the physical register, register pair or vector holding a Dalvik value.
- * The basic configuration of the storage (i.e. solo reg, pair, vector) is common across all
- * targets, but the encoding of the actual storage element is target independent.
+ * 16-bit representation of the physical register container holding a Dalvik value.
+ * The encoding allows up to 32 physical elements per storage class, and supports eight
+ * register container shapes.
*
- * The two most-significant bits describe the basic shape of the storage, while meaning of the
- * lower 14 bits depends on the shape:
+ * [V] [D] [HHHHH] [SSS] [F] [LLLLL]
*
- * [PW]
- * P: 0 -> pair, 1 -> solo (or vector)
- * W: 1 -> 64 bits, 0 -> 32 bits
+ * [LLLLL]
+ * Physical register number for the low or solo register.
+ * 0..31
*
- * [00] [xxxxxxxxxxxxxx] Invalid (typically all zeros)
- * [01] [HHHHHHH] [LLLLLLL] 64-bit storage, composed of 2 32-bit registers
- * [10] [0] [xxxxxx] [RRRRRRR] 32-bit solo register
- * [11] [0] [xxxxxx] [RRRRRRR] 64-bit solo register
- * [10] [1] [xxxxxx] [VVVVVVV] 32-bit vector storage
- * [11] [1] [xxxxxx] [VVVVVVV] 64-bit vector storage
+ * [F]
+ * Describes type of the [LLLLL] register.
+ * 0: Core
+ * 1: Floating point
*
- * x - don't care
- * L - low register number of a pair
- * H - high register number of a pair
- * R - register number of a solo reg
- * V - vector description
+ * [SSS]
+ * Shape of the register container.
+ * 000: Invalid
+ * 001: 32-bit solo register
+ * 010: 64-bit solo register
+ * 011: 64-bit pair consisting of two 32-bit solo registers
+ * 100: 128-bit solo register
+ * 101: 256-bit solo register
+ * 110: 512-bit solo register
+ * 111: 1024-bit solo register
*
- * Note that in all non-invalid cases, the low 7 bits must be sufficient to describe
- * whether the storage element is floating point (see IsFloatReg()).
+ * [HHHHH]
+ * Physical register number of the high register (valid only for register pair).
+ * 0..31
*
+ * [D]
+ * Describes type of the [HHHHH] register (valid only for register pair).
+ * 0: Core
+ * 1: Floating point
+ *
+ * [V]
+ * 0 -> Invalid
+ * 1 -> Valid
+ *
+ * Note that in all non-invalid cases, we can determine if the storage is floating point
+ * by testing bit 6. Though a mismatch appears to be permitted by the format, the [F][D] values
+ * from each half of a pair must match (this allows the high and low regs of a pair to be more
+ * easily individually manipulated).
+ *
+ * On some target architectures, the same underlying physical register container can be given
+ * different views. For example, Arm's 32-bit single-precision floating point registers
+ * s2 and s3 map to the low and high halves of double-precision d1. Similarly, X86's xmm3
+ * vector register can be viewed as 32-bit, 64-bit, 128-bit, etc. In these cases the use of
+ * one view will affect the other views. The RegStorage class does not concern itself
+ * with potential aliasing. That will be done using the associated RegisterInfo struct.
+ * Distinct RegStorage elements should be created for each view of a physical register
+ * container. The management of the aliased physical elements will be handled via RegisterInfo
+ * records.
*/
class RegStorage {
public:
enum RegStorageKind {
- kInvalid = 0x0000,
- k64BitPair = 0x4000,
- k32BitSolo = 0x8000,
- k64BitSolo = 0xc000,
- k32BitVector = 0xa000,
- k64BitVector = 0xe000,
- kPairMask = 0x8000,
- kPair = 0x0000,
- kSizeMask = 0x4000,
- k64Bit = 0x4000,
- k32Bit = 0x0000,
- kVectorMask = 0xa000,
- kVector = 0xa000,
- kSolo = 0x8000,
- kShapeMask = 0xc000,
- kKindMask = 0xe000
+ kValidMask = 0x8000,
+ kValid = 0x8000,
+ kInvalid = 0x0000,
+ kShapeMask = 0x01c0,
+ k32BitSolo = 0x0040,
+ k64BitSolo = 0x0080,
+ k64BitPair = 0x00c0,
+ k128BitSolo = 0x0100,
+ k256BitSolo = 0x0140,
+ k512BitSolo = 0x0180,
+ k1024BitSolo = 0x01c0,
+ k64BitMask = 0x0180,
+ k64Bits = 0x0080,
+ kShapeTypeMask = 0x01e0,
+ kFloatingPoint = 0x0020,
+ kCoreRegister = 0x0000,
};
- static const uint16_t kRegValMask = 0x007f;
- static const uint16_t kInvalidRegVal = 0x007f;
- static const uint16_t kHighRegShift = 7;
- static const uint16_t kHighRegMask = kRegValMask << kHighRegShift;
+ static const uint16_t kRegValMask = 0x01ff; // Num, type and shape.
+ static const uint16_t kRegTypeMask = 0x003f; // Num and type.
+ static const uint16_t kRegNumMask = 0x001f; // Num only.
+ static const uint16_t kMaxRegs = kRegValMask + 1;
+ // TODO: deprecate use of kInvalidRegVal and speed up GetReg().
+ static const uint16_t kInvalidRegVal = 0x01ff;
+ static const uint16_t kHighRegShift = 9;
+ static const uint16_t kShapeMaskShift = 6;
+ static const uint16_t kHighRegMask = (kRegTypeMask << kHighRegShift);
+ // Reg is [F][LLLLL], will override any existing shape and use rs_kind.
RegStorage(RegStorageKind rs_kind, int reg) {
- DCHECK_NE(rs_kind & kShapeMask, kInvalid);
- DCHECK_NE(rs_kind & kShapeMask, k64BitPair);
- DCHECK_EQ(rs_kind & ~kKindMask, 0);
- DCHECK_EQ(reg & ~kRegValMask, 0);
- reg_ = rs_kind | reg;
+ DCHECK_NE(rs_kind, k64BitPair);
+ DCHECK_EQ(rs_kind & ~kShapeMask, 0);
+ reg_ = kValid | rs_kind | (reg & kRegTypeMask);
}
RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg) {
DCHECK_EQ(rs_kind, k64BitPair);
- DCHECK_EQ(low_reg & ~kRegValMask, 0);
- DCHECK_EQ(high_reg & ~kRegValMask, 0);
- reg_ = rs_kind | (high_reg << kHighRegShift) | low_reg;
+ DCHECK_EQ(low_reg & kFloatingPoint, high_reg & kFloatingPoint);
+ reg_ = kValid | rs_kind | ((high_reg & kRegTypeMask) << kHighRegShift) | (low_reg & kRegTypeMask);
}
- explicit RegStorage(uint16_t val) : reg_(val) {}
+ constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
RegStorage() : reg_(kInvalid) {}
- ~RegStorage() {}
bool operator==(const RegStorage rhs) const {
return (reg_ == rhs.GetRawBits());
@@ -102,73 +130,127 @@ class RegStorage {
}
bool Valid() const {
- return ((reg_ & kShapeMask) != kInvalid);
+ return ((reg_ & kValidMask) == kValid);
}
bool Is32Bit() const {
- return ((reg_ & kSizeMask) == k32Bit);
+ return ((reg_ & kShapeMask) == k32BitSolo);
}
bool Is64Bit() const {
- return ((reg_ & kSizeMask) == k64Bit);
+ return ((reg_ & k64BitMask) == k64Bits);
}
bool IsPair() const {
- return ((reg_ & kPairMask) == kPair);
+ return ((reg_ & kShapeMask) == k64BitPair);
}
- bool IsSolo() const {
- return ((reg_ & kVectorMask) == kSolo);
+ bool IsFloat() const {
+ DCHECK(Valid());
+ return ((reg_ & kFloatingPoint) == kFloatingPoint);
}
- bool IsVector() const {
- return ((reg_ & kVectorMask) == kVector);
+ bool IsDouble() const {
+ DCHECK(Valid());
+ return (reg_ & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+ }
+
+ bool IsSingle() const {
+ DCHECK(Valid());
+ return (reg_ & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
+ }
+
+ static bool IsFloat(uint16_t reg) {
+ return ((reg & kFloatingPoint) == kFloatingPoint);
+ }
+
+ static bool IsDouble(uint16_t reg) {
+ return (reg & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
+ }
+
+ static bool IsSingle(uint16_t reg) {
+ return (reg & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
}
// Used to retrieve either the low register of a pair, or the only register.
int GetReg() const {
- DCHECK(!IsPair());
+ DCHECK(!IsPair()) << "reg_ = 0x" << std::hex << reg_;
return Valid() ? (reg_ & kRegValMask) : kInvalidRegVal;
}
+ // Sets shape, type and num of solo.
void SetReg(int reg) {
DCHECK(Valid());
+ DCHECK(!IsPair());
reg_ = (reg_ & ~kRegValMask) | reg;
}
+ // Set the reg number and type only, target remain 64-bit pair.
void SetLowReg(int reg) {
DCHECK(IsPair());
- reg_ = (reg_ & ~kRegValMask) | reg;
+ reg_ = (reg_ & ~kRegTypeMask) | (reg & kRegTypeMask);
}
- // Retrieve the least significant register of a pair.
+ // Retrieve the least significant register of a pair and return as 32-bit solo.
int GetLowReg() const {
DCHECK(IsPair());
- return (reg_ & kRegValMask);
+ return ((reg_ & kRegTypeMask) | k32BitSolo);
}
// Create a stand-alone RegStorage from the low reg of a pair.
RegStorage GetLow() const {
DCHECK(IsPair());
- return RegStorage(k32BitSolo, reg_ & kRegValMask);
+ return RegStorage(k32BitSolo, reg_ & kRegTypeMask);
}
// Retrieve the most significant register of a pair.
int GetHighReg() const {
DCHECK(IsPair());
- return (reg_ & kHighRegMask) >> kHighRegShift;
+ return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift);
}
// Create a stand-alone RegStorage from the high reg of a pair.
RegStorage GetHigh() const {
DCHECK(IsPair());
- return RegStorage(k32BitSolo, (reg_ & kHighRegMask) >> kHighRegShift);
+ return RegStorage(kValid | GetHighReg());
}
void SetHighReg(int reg) {
DCHECK(IsPair());
- reg_ = (reg_ & ~kHighRegMask) | (reg << kHighRegShift);
- DCHECK_EQ(GetHighReg(), reg);
+ reg_ = (reg_ & ~kHighRegMask) | ((reg & kRegTypeMask) << kHighRegShift);
+ }
+
+ // Return the register number of low or solo.
+ int GetRegNum() const {
+ return reg_ & kRegNumMask;
+ }
+
+ // Aliased double to low single.
+ RegStorage DoubleToLowSingle() const {
+ DCHECK(IsDouble());
+ return FloatSolo32(GetRegNum() << 1);
+ }
+
+ // Aliased double to high single.
+ RegStorage DoubleToHighSingle() const {
+ DCHECK(IsDouble());
+ return FloatSolo32((GetRegNum() << 1) + 1);
+ }
+
+ // Single to aliased double.
+ RegStorage SingleToDouble() const {
+ DCHECK(IsSingle());
+ return FloatSolo64(GetRegNum() >> 1);
+ }
+
+ // Is register number in 0..7?
+ bool Low8() const {
+ return GetRegNum() < 8;
+ }
+
+ // Is register number in 0..3?
+ bool Low4() const {
+ return GetRegNum() < 4;
}
// Combine 2 32-bit solo regs into a pair.
@@ -180,24 +262,61 @@ class RegStorage {
return RegStorage(k64BitPair, low.GetReg(), high.GetReg());
}
+ static bool SameRegType(RegStorage reg1, RegStorage reg2) {
+ return (reg1.IsDouble() == reg2.IsDouble()) && (reg1.IsSingle() == reg2.IsSingle());
+ }
+
+ static bool SameRegType(int reg1, int reg2) {
+ return (IsDouble(reg1) == IsDouble(reg2)) && (IsSingle(reg1) == IsSingle(reg2));
+ }
+
// Create a 32-bit solo.
static RegStorage Solo32(int reg_num) {
- return RegStorage(k32BitSolo, reg_num);
+ return RegStorage(k32BitSolo, reg_num & kRegTypeMask);
+ }
+
+ // Create a floating point 32-bit solo.
+ static RegStorage FloatSolo32(int reg_num) {
+ return RegStorage(k32BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
}
// Create a 64-bit solo.
static RegStorage Solo64(int reg_num) {
- return RegStorage(k64BitSolo, reg_num);
+ return RegStorage(k64BitSolo, reg_num & kRegTypeMask);
+ }
+
+ // Create a floating point 64-bit solo.
+ static RegStorage FloatSolo64(int reg_num) {
+ return RegStorage(k64BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
}
static RegStorage InvalidReg() {
return RegStorage(kInvalid);
}
+ static uint16_t RegNum(int raw_reg_bits) {
+ return raw_reg_bits & kRegNumMask;
+ }
+
int GetRawBits() const {
return reg_;
}
+ size_t StorageSize() {
+ switch (reg_ & kShapeMask) {
+ case kInvalid: return 0;
+ case k32BitSolo: return 4;
+ case k64BitSolo: return 8;
+ case k64BitPair: return 8; // Is this useful? Might want to disallow taking size of pair.
+ case k128BitSolo: return 16;
+ case k256BitSolo: return 32;
+ case k512BitSolo: return 64;
+ case k1024BitSolo: return 128;
+ default: LOG(FATAL) << "Unexpected shap";
+ }
+ return 0;
+ }
+
private:
uint16_t reg_;
};