Chromium Code Reviews| Index: src/arm/assembler-arm.h |
| diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h |
| index 3b9bb804fd331c144563d6522239c6967933a817..46ca939ae71e9e51ddc819672ed79479cad03826 100644 |
| --- a/src/arm/assembler-arm.h |
| +++ b/src/arm/assembler-arm.h |
| @@ -47,6 +47,114 @@ |
| namespace v8 { |
| namespace internal { |
| +// CpuFeatures keeps track of which features are supported by the target CPU. |
| +// Supported features must be enabled by a Scope before use. |
| +class CpuFeatures : public AllStatic { |
| + public: |
| + // Detect features of the target CPU. Set safe defaults if the serializer |
| + // is enabled (snapshots must be portable). |
| + static void Probe(); |
| + |
| + // Check whether a feature is supported by the target CPU. |
| + static bool IsSupported(CpuFeature f) { |
| + ASSERT(initialized_); |
| + if (f == VFP3 && !FLAG_enable_vfp3) return false; |
| + if (f == VFP2 && !FLAG_enable_vfp2) return false; |
| + if (f == SUDIV && !FLAG_enable_sudiv) return false; |
| + if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) { |
| + return false; |
| + } |
| + return (supported_ & (1u << f)) != 0; |
| + } |
| + |
| +#ifdef DEBUG |
| + // Check whether a feature is currently enabled. |
| + static bool IsEnabled(CpuFeature f) { |
| + ASSERT(initialized_); |
| + Isolate* isolate = Isolate::UncheckedCurrent(); |
| + if (isolate == NULL) { |
| + // When no isolate is available, work as if we're running in |
| + // release mode. |
| + return IsSupported(f); |
| + } |
| + unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features()); |
| + return (enabled & (1u << f)) != 0; |
| + } |
| +#endif |
| + |
| + // Enable a specified feature within a scope. |
| + class Scope BASE_EMBEDDED { |
| +#ifdef DEBUG |
| + |
| + public: |
| + explicit Scope(CpuFeature f) { |
| + unsigned mask = 1u << f; |
| + // VFP2 and ARMv7 are implied by VFP3. |
| + if (f == VFP3) mask |= 1u << VFP2 | 1u << ARMv7; |
| + ASSERT(CpuFeatures::IsSupported(f)); |
| + ASSERT(!Serializer::enabled() || |
| + (CpuFeatures::found_by_runtime_probing_ & mask) == 0); |
| + isolate_ = Isolate::UncheckedCurrent(); |
| + old_enabled_ = 0; |
| + if (isolate_ != NULL) { |
| + old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features()); |
| + isolate_->set_enabled_cpu_features(old_enabled_ | mask); |
| + } |
| + } |
| + ~Scope() { |
| + ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_); |
| + if (isolate_ != NULL) { |
| + isolate_->set_enabled_cpu_features(old_enabled_); |
| + } |
| + } |
| + |
| + private: |
| + Isolate* isolate_; |
| + unsigned old_enabled_; |
| +#else |
| + |
| + public: |
| + explicit Scope(CpuFeature f) {} |
| +#endif |
| + }; |
| + |
| + class TryForceFeatureScope BASE_EMBEDDED { |
| + public: |
| + explicit TryForceFeatureScope(CpuFeature f) |
| + : old_supported_(CpuFeatures::supported_) { |
| + if (CanForce()) { |
| + CpuFeatures::supported_ |= (1u << f); |
| + } |
| + } |
| + |
| + ~TryForceFeatureScope() { |
| + if (CanForce()) { |
| + CpuFeatures::supported_ = old_supported_; |
| + } |
| + } |
| + |
| + private: |
| + static bool CanForce() { |
| + // It's only safe to temporarily force support of CPU features |
| + // when there's only a single isolate, which is guaranteed when |
| + // the serializer is enabled. |
| + return Serializer::enabled(); |
| + } |
| + |
| + const unsigned old_supported_; |
| + }; |
| + |
| + private: |
| +#ifdef DEBUG |
| + static bool initialized_; |
| +#endif |
| + static unsigned supported_; |
| + static unsigned found_by_runtime_probing_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CpuFeatures); |
| +}; |
| + |
| + |
| // CPU Registers. |
| // |
| // 1) We would prefer to use an enum, but enum values are assignment- |
| @@ -190,24 +298,32 @@ struct SwVfpRegister { |
| // Double word VFP register. |
| struct DwVfpRegister { |
| - static const int kNumRegisters = 16; |
| + static const int kNumRegisters = 32; |
| // A few double registers are reserved: one as a scratch register and one to |
| // hold 0.0, that does not fit in the immediate field of vmov instructions. |
| // d14: 0.0 |
| // d15: scratch register. |
| static const int kNumReservedRegisters = 2; |
| - static const int kNumAllocatableRegisters = kNumRegisters - |
| - kNumReservedRegisters; |
| + static int NumAvailableRegisters() { |
| + return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16; |
| + } |
| + static int NumAllocatableRegisters() { |
| + return NumAvailableRegisters() - kNumReservedRegisters; |
| + } |
| inline static int ToAllocationIndex(DwVfpRegister reg); |
| static DwVfpRegister FromAllocationIndex(int index) { |
| - ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| + ASSERT(index >= 0 && index < NumAllocatableRegisters()); |
| + if (index >= 14) |
|
ulan
2012/12/17 10:44:52
Here and below we can use kDoubleRegZero.code() in
hans
2012/12/17 12:31:44
I don't think that would work, since kDoubleRegZer
ulan
2012/12/17 13:03:36
I see. Yep, putting FromAllocationIndex near the T
hans
2012/12/17 13:53:21
Cool. I've moved it and AllocationIndexToString.
|
| + return from_code(index + kNumReservedRegisters); |
| return from_code(index); |
| } |
| static const char* AllocationIndexToString(int index) { |
| - ASSERT(index >= 0 && index < kNumAllocatableRegisters); |
| + ASSERT(index >= 0 && index < NumAllocatableRegisters()); |
| + if (index >= 14) |
| + index += kNumReservedRegisters; |
| const char* const names[] = { |
| "d0", |
| "d1", |
| @@ -222,7 +338,25 @@ struct DwVfpRegister { |
| "d10", |
| "d11", |
| "d12", |
| - "d13" |
| + "d13", |
| + "d14", |
| + "d15", |
| + "d16", |
| + "d17", |
| + "d18", |
| + "d19", |
| + "d20", |
| + "d21", |
| + "d22", |
| + "d23", |
| + "d24", |
| + "d25", |
| + "d26", |
| + "d27", |
| + "d28", |
| + "d29", |
| + "d30", |
| + "d31" |
| }; |
| return names[index]; |
| } |
| @@ -232,10 +366,12 @@ struct DwVfpRegister { |
| return r; |
| } |
| - // Supporting d0 to d15, can be later extended to d31. |
| - bool is_valid() const { return 0 <= code_ && code_ < 16; } |
| + bool is_valid() const { |
| + return 0 <= code_ && code_ < NumAvailableRegisters(); |
| + } |
| bool is(DwVfpRegister reg) const { return code_ == reg.code_; } |
| SwVfpRegister low() const { |
| + ASSERT(code_ < 16); |
| SwVfpRegister reg; |
| reg.code_ = code_ * 2; |
| @@ -243,6 +379,7 @@ struct DwVfpRegister { |
| return reg; |
| } |
| SwVfpRegister high() const { |
| + ASSERT(code_ < 16); |
| SwVfpRegister reg; |
| reg.code_ = (code_ * 2) + 1; |
| @@ -322,8 +459,24 @@ const DwVfpRegister d12 = { 12 }; |
| const DwVfpRegister d13 = { 13 }; |
| const DwVfpRegister d14 = { 14 }; |
| const DwVfpRegister d15 = { 15 }; |
| - |
| -// Aliases for double registers. Defined using #define instead of |
| +const DwVfpRegister d16 = { 16 }; |
| +const DwVfpRegister d17 = { 17 }; |
| +const DwVfpRegister d18 = { 18 }; |
| +const DwVfpRegister d19 = { 19 }; |
| +const DwVfpRegister d20 = { 20 }; |
| +const DwVfpRegister d21 = { 21 }; |
| +const DwVfpRegister d22 = { 22 }; |
| +const DwVfpRegister d23 = { 23 }; |
| +const DwVfpRegister d24 = { 24 }; |
| +const DwVfpRegister d25 = { 25 }; |
| +const DwVfpRegister d26 = { 26 }; |
| +const DwVfpRegister d27 = { 27 }; |
| +const DwVfpRegister d28 = { 28 }; |
| +const DwVfpRegister d29 = { 29 }; |
| +const DwVfpRegister d30 = { 30 }; |
| +const DwVfpRegister d31 = { 31 }; |
| + |
| +// Aliases for double registers. Defined using #define instead of |
| // "static const DwVfpRegister&" because Clang complains otherwise when a |
| // compilation unit that includes this header doesn't use the variables. |
| #define kFirstCalleeSavedDoubleReg d8 |
| @@ -498,114 +651,6 @@ class MemOperand BASE_EMBEDDED { |
| friend class Assembler; |
| }; |
| -// CpuFeatures keeps track of which features are supported by the target CPU. |
| -// Supported features must be enabled by a Scope before use. |
| -class CpuFeatures : public AllStatic { |
| - public: |
| - // Detect features of the target CPU. Set safe defaults if the serializer |
| - // is enabled (snapshots must be portable). |
| - static void Probe(); |
| - |
| - // Check whether a feature is supported by the target CPU. |
| - static bool IsSupported(CpuFeature f) { |
| - ASSERT(initialized_); |
| - if (f == VFP3 && !FLAG_enable_vfp3) return false; |
| - if (f == VFP2 && !FLAG_enable_vfp2) return false; |
| - if (f == SUDIV && !FLAG_enable_sudiv) return false; |
| - if (f == UNALIGNED_ACCESSES && !FLAG_enable_unaligned_accesses) { |
| - return false; |
| - } |
| - return (supported_ & (1u << f)) != 0; |
| - } |
| - |
| -#ifdef DEBUG |
| - // Check whether a feature is currently enabled. |
| - static bool IsEnabled(CpuFeature f) { |
| - ASSERT(initialized_); |
| - Isolate* isolate = Isolate::UncheckedCurrent(); |
| - if (isolate == NULL) { |
| - // When no isolate is available, work as if we're running in |
| - // release mode. |
| - return IsSupported(f); |
| - } |
| - unsigned enabled = static_cast<unsigned>(isolate->enabled_cpu_features()); |
| - return (enabled & (1u << f)) != 0; |
| - } |
| -#endif |
| - |
| - // Enable a specified feature within a scope. |
| - class Scope BASE_EMBEDDED { |
| -#ifdef DEBUG |
| - |
| - public: |
| - explicit Scope(CpuFeature f) { |
| - unsigned mask = 1u << f; |
| - // VFP2 and ARMv7 are implied by VFP3. |
| - if (f == VFP3) mask |= 1u << VFP2 | 1u << ARMv7; |
| - ASSERT(CpuFeatures::IsSupported(f)); |
| - ASSERT(!Serializer::enabled() || |
| - (CpuFeatures::found_by_runtime_probing_ & mask) == 0); |
| - isolate_ = Isolate::UncheckedCurrent(); |
| - old_enabled_ = 0; |
| - if (isolate_ != NULL) { |
| - old_enabled_ = static_cast<unsigned>(isolate_->enabled_cpu_features()); |
| - isolate_->set_enabled_cpu_features(old_enabled_ | mask); |
| - } |
| - } |
| - ~Scope() { |
| - ASSERT_EQ(Isolate::UncheckedCurrent(), isolate_); |
| - if (isolate_ != NULL) { |
| - isolate_->set_enabled_cpu_features(old_enabled_); |
| - } |
| - } |
| - |
| - private: |
| - Isolate* isolate_; |
| - unsigned old_enabled_; |
| -#else |
| - |
| - public: |
| - explicit Scope(CpuFeature f) {} |
| -#endif |
| - }; |
| - |
| - class TryForceFeatureScope BASE_EMBEDDED { |
| - public: |
| - explicit TryForceFeatureScope(CpuFeature f) |
| - : old_supported_(CpuFeatures::supported_) { |
| - if (CanForce()) { |
| - CpuFeatures::supported_ |= (1u << f); |
| - } |
| - } |
| - |
| - ~TryForceFeatureScope() { |
| - if (CanForce()) { |
| - CpuFeatures::supported_ = old_supported_; |
| - } |
| - } |
| - |
| - private: |
| - static bool CanForce() { |
| - // It's only safe to temporarily force support of CPU features |
| - // when there's only a single isolate, which is guaranteed when |
| - // the serializer is enabled. |
| - return Serializer::enabled(); |
| - } |
| - |
| - const unsigned old_supported_; |
| - }; |
| - |
| - private: |
| -#ifdef DEBUG |
| - static bool initialized_; |
| -#endif |
| - static unsigned supported_; |
| - static unsigned found_by_runtime_probing_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(CpuFeatures); |
| -}; |
| - |
| - |
| extern const Instr kMovLrPc; |
| extern const Instr kLdrPCMask; |
| extern const Instr kLdrPCPattern; |
| @@ -994,10 +1039,7 @@ class Assembler : public AssemblerBase { |
| LFlag l = Short); // v5 and above |
| // Support for VFP. |
| - // All these APIs support S0 to S31 and D0 to D15. |
| - // Currently these APIs do not support extended D registers, i.e, D16 to D31. |
| - // However, some simple modifications can allow |
| - // these APIs to support D16 to D31. |
| + // All these APIs support S0 to S31 and D0 to D31. |
| void vldr(const DwVfpRegister dst, |
| const Register base, |
| @@ -1066,6 +1108,10 @@ class Assembler : public AssemblerBase { |
| const DwVfpRegister src, |
| const Condition cond = al); |
| void vmov(const DwVfpRegister dst, |
| + int x, |
|
ulan
2012/12/17 10:44:52
I wonder if there is more descriptive name than 'x
hans
2012/12/17 12:31:44
How about "index"?
ulan
2012/12/17 13:03:36
Yep, I like it more.
hans
2012/12/17 13:53:21
Done.
|
| + const Register src, |
| + const Condition cond = al); |
| + void vmov(const DwVfpRegister dst, |
| const Register src1, |
| const Register src2, |
| const Condition cond = al); |