michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_mips_Architecture_mips_h michael@0: #define jit_mips_Architecture_mips_h michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "js/Utility.h" michael@0: michael@0: // gcc appears to use _mips_hard_float to denote michael@0: // that the target is a hard-float target. michael@0: #ifdef _mips_hard_float michael@0: #define JS_CODEGEN_MIPS_HARDFP michael@0: #endif michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: // Shadow stack space is not required on MIPS. michael@0: static const uint32_t ShadowStackSpace = 0; michael@0: michael@0: // These offsets are specific to nunboxing, and capture offsets into the michael@0: // components of a js::Value. michael@0: // Size of MIPS32 general purpose registers is 32 bits. michael@0: static const int32_t NUNBOX32_TYPE_OFFSET = 4; michael@0: static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0; michael@0: michael@0: // Size of each bailout table entry. michael@0: // For MIPS this is 2 instructions relative call. michael@0: static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void *); michael@0: michael@0: class Registers michael@0: { michael@0: public: michael@0: enum RegisterID { michael@0: r0 = 0, michael@0: r1, michael@0: r2, michael@0: r3, michael@0: r4, michael@0: r5, michael@0: r6, michael@0: r7, michael@0: r8, michael@0: r9, michael@0: r10, michael@0: r11, michael@0: r12, michael@0: r13, michael@0: r14, michael@0: r15, michael@0: r16, michael@0: r17, michael@0: r18, michael@0: r19, michael@0: r20, michael@0: r21, michael@0: r22, michael@0: r23, michael@0: r24, michael@0: r25, michael@0: r26, michael@0: r27, michael@0: r28, michael@0: r29, michael@0: r30, michael@0: r31, michael@0: zero = r0, michael@0: at = r1, michael@0: v0 = r2, michael@0: v1 = r3, michael@0: a0 = r4, michael@0: a1 = r5, michael@0: a2 = r6, michael@0: a3 = r7, michael@0: t0 = r8, michael@0: t1 = r9, michael@0: t2 = r10, michael@0: t3 = r11, michael@0: t4 = r12, michael@0: t5 = r13, michael@0: t6 = r14, michael@0: t7 = r15, michael@0: s0 = r16, michael@0: s1 = r17, michael@0: s2 = r18, michael@0: s3 = r19, michael@0: s4 = r20, michael@0: s5 = r21, michael@0: s6 = r22, michael@0: s7 = r23, michael@0: t8 = r24, michael@0: t9 = r25, michael@0: k0 = r26, michael@0: k1 = r27, michael@0: gp = r28, michael@0: sp = r29, michael@0: fp = r30, michael@0: ra = r31, michael@0: invalid_reg michael@0: }; michael@0: typedef RegisterID Code; michael@0: michael@0: static const char *GetName(Code code) { michael@0: static const char * const Names[] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", michael@0: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", michael@0: "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", michael@0: "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"}; michael@0: return Names[code]; michael@0: } michael@0: static const char *GetName(uint32_t i) { michael@0: JS_ASSERT(i < Total); michael@0: return GetName(Code(i)); michael@0: } michael@0: michael@0: static Code FromName(const char *name); michael@0: michael@0: static const Code StackPointer = sp; michael@0: static const Code Invalid = invalid_reg; michael@0: michael@0: static const uint32_t Total = 32; michael@0: static const uint32_t Allocatable = 14; michael@0: michael@0: static const uint32_t AllMask = 0xffffffff; michael@0: static const uint32_t ArgRegMask = (1 << a0) | (1 << a1) | (1 << a2) | (1 << a3); michael@0: michael@0: static const uint32_t VolatileMask = michael@0: (1 << Registers::v0) | michael@0: (1 << Registers::v1) | michael@0: (1 << Registers::a0) | michael@0: (1 << Registers::a1) | michael@0: (1 << Registers::a2) | michael@0: (1 << Registers::a3) | michael@0: (1 << Registers::t0) | michael@0: (1 << Registers::t1) | michael@0: (1 << Registers::t2) | michael@0: (1 << Registers::t3) | michael@0: (1 << Registers::t4) | michael@0: (1 << Registers::t5) | michael@0: (1 << Registers::t6) | michael@0: (1 << Registers::t7); michael@0: michael@0: static const uint32_t NonVolatileMask = michael@0: (1 << Registers::s0) | michael@0: (1 << Registers::s1) | michael@0: (1 << Registers::s2) | michael@0: (1 << Registers::s3) | michael@0: (1 << Registers::s4) | michael@0: (1 << Registers::s5) | michael@0: (1 << Registers::s6) | michael@0: (1 << Registers::s7); michael@0: michael@0: static const uint32_t WrapperMask = michael@0: VolatileMask | // = arguments michael@0: (1 << Registers::t0) | // = outReg michael@0: (1 << Registers::t1); // = argBase michael@0: michael@0: static const uint32_t NonAllocatableMask = michael@0: (1 << Registers::zero) | michael@0: (1 << Registers::at) | // at = scratch michael@0: (1 << Registers::t8) | // t8 = scratch michael@0: (1 << Registers::t9) | // t9 = scratch michael@0: (1 << Registers::k0) | michael@0: (1 << Registers::k1) | michael@0: (1 << Registers::gp) | michael@0: (1 << Registers::sp) | michael@0: (1 << Registers::fp) | michael@0: (1 << Registers::ra); michael@0: michael@0: // Registers that can be allocated without being saved, generally. michael@0: static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask; michael@0: michael@0: // Registers returned from a JS -> JS call. michael@0: static const uint32_t JSCallMask = michael@0: (1 << Registers::v0) | michael@0: (1 << Registers::v1); michael@0: michael@0: // Registers returned from a JS -> C call. michael@0: static const uint32_t CallMask = michael@0: (1 << Registers::v0) | michael@0: (1 << Registers::v1); // used for double-size returns michael@0: michael@0: static const uint32_t AllocatableMask = AllMask & ~NonAllocatableMask; michael@0: }; michael@0: michael@0: // Smallest integer type that can hold a register bitmask. michael@0: typedef uint32_t PackedRegisterMask; michael@0: michael@0: michael@0: // MIPS32 can have two types of floating-point coprocessors: michael@0: // - 32 bit floating-point coprocessor - In this case, there are 32 single michael@0: // precision registers and pairs of even and odd float registers are used as michael@0: // double precision registers. Example: f0 (double) is composed of michael@0: // f0 and f1 (single). michael@0: // - 64 bit floating-point coprocessor - In this case, there are 32 double michael@0: // precision register which can also be used as single precision registers. michael@0: michael@0: // When using O32 ABI, floating-point coprocessor is 32 bit michael@0: // When using N32 ABI, floating-point coprocessor is 64 bit. michael@0: class FloatRegisters michael@0: { michael@0: public: michael@0: enum FPRegisterID { michael@0: f0 = 0, michael@0: f1, michael@0: f2, michael@0: f3, michael@0: f4, michael@0: f5, michael@0: f6, michael@0: f7, michael@0: f8, michael@0: f9, michael@0: f10, michael@0: f11, michael@0: f12, michael@0: f13, michael@0: f14, michael@0: f15, michael@0: f16, michael@0: f17, michael@0: f18, michael@0: f19, michael@0: f20, michael@0: f21, michael@0: f22, michael@0: f23, michael@0: f24, michael@0: f25, michael@0: f26, michael@0: f27, michael@0: f28, michael@0: f29, michael@0: f30, michael@0: f31, michael@0: invalid_freg michael@0: }; michael@0: typedef FPRegisterID Code; michael@0: michael@0: static const char *GetName(Code code) { michael@0: static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", michael@0: "f8", "f9", "f10", "f11", "f12", "f13", michael@0: "f14", "f15", "f16", "f17", "f18", "f19", michael@0: "f20", "f21", "f22", "f23", "f24", "f25", michael@0: "f26", "f27", "f28", "f29", "f30", "f31"}; michael@0: return Names[code]; michael@0: } michael@0: static const char *GetName(uint32_t i) { michael@0: JS_ASSERT(i < Total); michael@0: return GetName(Code(i)); michael@0: } michael@0: michael@0: static Code FromName(const char *name); michael@0: michael@0: static const Code Invalid = invalid_freg; michael@0: michael@0: static const uint32_t Total = 32; michael@0: // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32 michael@0: // only. For now we don't allocate odd regs for O32 ABI. michael@0: static const uint32_t Allocatable = 14; michael@0: michael@0: static const uint32_t AllMask = 0xffffffff; michael@0: michael@0: static const uint32_t VolatileMask = michael@0: (1 << FloatRegisters::f0) | michael@0: (1 << FloatRegisters::f2) | michael@0: (1 << FloatRegisters::f4) | michael@0: (1 << FloatRegisters::f6) | michael@0: (1 << FloatRegisters::f8) | michael@0: (1 << FloatRegisters::f10) | michael@0: (1 << FloatRegisters::f12) | michael@0: (1 << FloatRegisters::f14) | michael@0: (1 << FloatRegisters::f16) | michael@0: (1 << FloatRegisters::f18); michael@0: static const uint32_t NonVolatileMask = michael@0: (1 << FloatRegisters::f20) | michael@0: (1 << FloatRegisters::f22) | michael@0: (1 << FloatRegisters::f24) | michael@0: (1 << FloatRegisters::f26) | michael@0: (1 << FloatRegisters::f28) | michael@0: (1 << FloatRegisters::f30); michael@0: michael@0: static const uint32_t WrapperMask = VolatileMask; michael@0: michael@0: // :TODO: (Bug 972836) // Fix this once odd regs can be used as float32 michael@0: // only. For now we don't allocate odd regs for O32 ABI. michael@0: static const uint32_t NonAllocatableMask = michael@0: (1 << FloatRegisters::f1) | michael@0: (1 << FloatRegisters::f3) | michael@0: (1 << FloatRegisters::f5) | michael@0: (1 << FloatRegisters::f7) | michael@0: (1 << FloatRegisters::f9) | michael@0: (1 << FloatRegisters::f11) | michael@0: (1 << FloatRegisters::f13) | michael@0: (1 << FloatRegisters::f15) | michael@0: (1 << FloatRegisters::f17) | michael@0: (1 << FloatRegisters::f19) | michael@0: (1 << FloatRegisters::f21) | michael@0: (1 << FloatRegisters::f23) | michael@0: (1 << FloatRegisters::f25) | michael@0: (1 << FloatRegisters::f27) | michael@0: (1 << FloatRegisters::f29) | michael@0: (1 << FloatRegisters::f31) | michael@0: // f18 and f16 are MIPS scratch float registers. michael@0: (1 << FloatRegisters::f16) | michael@0: (1 << FloatRegisters::f18); michael@0: michael@0: // Registers that can be allocated without being saved, generally. michael@0: static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask; michael@0: michael@0: static const uint32_t AllocatableMask = AllMask & ~NonAllocatableMask; michael@0: }; michael@0: michael@0: uint32_t GetMIPSFlags(); michael@0: bool hasFPU(); michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_mips_Architecture_mips_h */