summaryrefslogtreecommitdiff
path: root/deps/v8/src/mips/assembler-mips.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/mips/assembler-mips.h')
-rw-r--r--deps/v8/src/mips/assembler-mips.h431
1 files changed, 59 insertions, 372 deletions
diff --git a/deps/v8/src/mips/assembler-mips.h b/deps/v8/src/mips/assembler-mips.h
index d535f1e923..21409f9bf4 100644
--- a/deps/v8/src/mips/assembler-mips.h
+++ b/deps/v8/src/mips/assembler-mips.h
@@ -41,344 +41,17 @@
#include <set>
#include "src/assembler.h"
+#include "src/external-reference.h"
+#include "src/label.h"
#include "src/mips/constants-mips.h"
+#include "src/mips/register-mips.h"
+#include "src/objects/smi.h"
namespace v8 {
namespace internal {
-// clang-format off
-#define GENERAL_REGISTERS(V) \
- V(zero_reg) V(at) V(v0) V(v1) V(a0) V(a1) V(a2) V(a3) \
- V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(t7) \
- V(s0) V(s1) V(s2) V(s3) V(s4) V(s5) V(s6) V(s7) V(t8) V(t9) \
- V(k0) V(k1) V(gp) V(sp) V(fp) V(ra)
-
-#define ALLOCATABLE_GENERAL_REGISTERS(V) \
- V(a0) V(a1) V(a2) V(a3) \
- V(t0) V(t1) V(t2) V(t3) V(t4) V(t5) V(t6) V(s7) \
- V(v0) V(v1)
-
-#define DOUBLE_REGISTERS(V) \
- V(f0) V(f1) V(f2) V(f3) V(f4) V(f5) V(f6) V(f7) \
- V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
- V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
- V(f24) V(f25) V(f26) V(f27) V(f28) V(f29) V(f30) V(f31)
-
-#define FLOAT_REGISTERS DOUBLE_REGISTERS
-#define SIMD128_REGISTERS(V) \
- V(w0) V(w1) V(w2) V(w3) V(w4) V(w5) V(w6) V(w7) \
- V(w8) V(w9) V(w10) V(w11) V(w12) V(w13) V(w14) V(w15) \
- V(w16) V(w17) V(w18) V(w19) V(w20) V(w21) V(w22) V(w23) \
- V(w24) V(w25) V(w26) V(w27) V(w28) V(w29) V(w30) V(w31)
-
-#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
- V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
- V(f16) V(f18) V(f20) V(f22) V(f24)
-// clang-format on
-
-// Register lists.
-// Note that the bit values must match those used in actual instruction
-// encoding.
-const int kNumRegs = 32;
-
-const RegList kJSCallerSaved = 1 << 2 | // v0
- 1 << 3 | // v1
- 1 << 4 | // a0
- 1 << 5 | // a1
- 1 << 6 | // a2
- 1 << 7 | // a3
- 1 << 8 | // t0
- 1 << 9 | // t1
- 1 << 10 | // t2
- 1 << 11 | // t3
- 1 << 12 | // t4
- 1 << 13 | // t5
- 1 << 14 | // t6
- 1 << 15; // t7
-
-const int kNumJSCallerSaved = 14;
-
-// Callee-saved registers preserved when switching from C to JavaScript.
-const RegList kCalleeSaved = 1 << 16 | // s0
- 1 << 17 | // s1
- 1 << 18 | // s2
- 1 << 19 | // s3
- 1 << 20 | // s4
- 1 << 21 | // s5
- 1 << 22 | // s6 (roots in Javascript code)
- 1 << 23 | // s7 (cp in Javascript code)
- 1 << 30; // fp/s8
-
-const int kNumCalleeSaved = 9;
-
-const RegList kCalleeSavedFPU = 1 << 20 | // f20
- 1 << 22 | // f22
- 1 << 24 | // f24
- 1 << 26 | // f26
- 1 << 28 | // f28
- 1 << 30; // f30
-
-const int kNumCalleeSavedFPU = 6;
-
-const RegList kCallerSavedFPU = 1 << 0 | // f0
- 1 << 2 | // f2
- 1 << 4 | // f4
- 1 << 6 | // f6
- 1 << 8 | // f8
- 1 << 10 | // f10
- 1 << 12 | // f12
- 1 << 14 | // f14
- 1 << 16 | // f16
- 1 << 18; // f18
-
-// Number of registers for which space is reserved in safepoints. Must be a
-// multiple of 8.
-const int kNumSafepointRegisters = 24;
-
-// Define the list of registers actually saved at safepoints.
-// Note that the number of saved registers may be smaller than the reserved
-// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
-const RegList kSafepointSavedRegisters = kJSCallerSaved | kCalleeSaved;
-const int kNumSafepointSavedRegisters = kNumJSCallerSaved + kNumCalleeSaved;
-
-const int kUndefIndex = -1;
-// Map with indexes on stack that corresponds to codes of saved registers.
-const int kSafepointRegisterStackIndexMap[kNumRegs] = {kUndefIndex, // zero_reg
- kUndefIndex, // at
- 0, // v0
- 1, // v1
- 2, // a0
- 3, // a1
- 4, // a2
- 5, // a3
- 6, // t0
- 7, // t1
- 8, // t2
- 9, // t3
- 10, // t4
- 11, // t5
- 12, // t6
- 13, // t7
- 14, // s0
- 15, // s1
- 16, // s2
- 17, // s3
- 18, // s4
- 19, // s5
- 20, // s6
- 21, // s7
- kUndefIndex, // t8
- kUndefIndex, // t9
- kUndefIndex, // k0
- kUndefIndex, // k1
- kUndefIndex, // gp
- kUndefIndex, // sp
- 22, // fp
- kUndefIndex};
-
-// CPU Registers.
-//
-// 1) We would prefer to use an enum, but enum values are assignment-
-// compatible with int, which has caused code-generation bugs.
-//
-// 2) We would prefer to use a class instead of a struct but we don't like
-// the register initialization to depend on the particular initialization
-// order (which appears to be different on OS X, Linux, and Windows for the
-// installed versions of C++ we tried). Using a struct permits C-style
-// "initialization". Also, the Register objects cannot be const as this
-// forces initialization stubs in MSVC, making us dependent on initialization
-// order.
-//
-// 3) By not using an enum, we are possibly preventing the compiler from
-// doing certain constant folds, which may significantly reduce the
-// code generated for some assembly instructions (because they boil down
-// to a few constants). If this is a problem, we could change the code
-// such that we use an enum in optimized mode, and the struct in debug
-// mode. This way we get the compile-time error checking in debug mode
-// and best performance in optimized code.
-
-
-// -----------------------------------------------------------------------------
-// Implementation of Register and FPURegister.
-
-enum RegisterCode {
-#define REGISTER_CODE(R) kRegCode_##R,
- GENERAL_REGISTERS(REGISTER_CODE)
-#undef REGISTER_CODE
- kRegAfterLast
-};
-
-class Register : public RegisterBase<Register, kRegAfterLast> {
- public:
-#if defined(V8_TARGET_LITTLE_ENDIAN)
- static constexpr int kMantissaOffset = 0;
- static constexpr int kExponentOffset = 4;
-#elif defined(V8_TARGET_BIG_ENDIAN)
- static constexpr int kMantissaOffset = 4;
- static constexpr int kExponentOffset = 0;
-#else
-#error Unknown endianness
-#endif
-
- private:
- friend class RegisterBase;
- explicit constexpr Register(int code) : RegisterBase(code) {}
-};
-
-// s7: context register
-// s3: scratch register
-// s4: scratch register 2
-#define DECLARE_REGISTER(R) \
- constexpr Register R = Register::from_code<kRegCode_##R>();
-GENERAL_REGISTERS(DECLARE_REGISTER)
-#undef DECLARE_REGISTER
-constexpr Register no_reg = Register::no_reg();
-
-int ToNumber(Register reg);
-
-Register ToRegister(int num);
-
-constexpr bool kPadArguments = false;
-constexpr bool kSimpleFPAliasing = true;
-constexpr bool kSimdMaskRegisters = false;
-
-enum DoubleRegisterCode {
-#define REGISTER_CODE(R) kDoubleCode_##R,
- DOUBLE_REGISTERS(REGISTER_CODE)
-#undef REGISTER_CODE
- kDoubleAfterLast
-};
-
-// Coprocessor register.
-class FPURegister : public RegisterBase<FPURegister, kDoubleAfterLast> {
- public:
- FPURegister low() const {
- // Find low reg of a Double-reg pair, which is the reg itself.
- DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
- return FPURegister::from_code(code());
- }
- FPURegister high() const {
- // Find high reg of a Doubel-reg pair, which is reg + 1.
- DCHECK_EQ(code() % 2, 0); // Specified Double reg must be even.
- return FPURegister::from_code(code() + 1);
- }
-
- private:
- friend class RegisterBase;
- explicit constexpr FPURegister(int code) : RegisterBase(code) {}
-};
-
-enum MSARegisterCode {
-#define REGISTER_CODE(R) kMsaCode_##R,
- SIMD128_REGISTERS(REGISTER_CODE)
-#undef REGISTER_CODE
- kMsaAfterLast
-};
-
-// MIPS SIMD (MSA) register
-class MSARegister : public RegisterBase<MSARegister, kMsaAfterLast> {
- friend class RegisterBase;
- explicit constexpr MSARegister(int code) : RegisterBase(code) {}
-};
-
-// A few double registers are reserved: one as a scratch register and one to
-// hold 0.0.
-// f28: 0.0
-// f30: scratch register.
-
-// V8 now supports the O32 ABI, and the FPU Registers are organized as 32
-// 32-bit registers, f0 through f31. When used as 'double' they are used
-// in pairs, starting with the even numbered register. So a double operation
-// on f0 really uses f0 and f1.
-// (Modern mips hardware also supports 32 64-bit registers, via setting
-// (priviledged) Status Register FR bit to 1. This is used by the N32 ABI,
-// but it is not in common use. Someday we will want to support this in v8.)
-
-// For O32 ABI, Floats and Doubles refer to same set of 32 32-bit registers.
-typedef FPURegister FloatRegister;
-
-typedef FPURegister DoubleRegister;
-
-#define DECLARE_DOUBLE_REGISTER(R) \
- constexpr DoubleRegister R = DoubleRegister::from_code<kDoubleCode_##R>();
-DOUBLE_REGISTERS(DECLARE_DOUBLE_REGISTER)
-#undef DECLARE_DOUBLE_REGISTER
-
-constexpr DoubleRegister no_dreg = DoubleRegister::no_reg();
-
-// SIMD registers.
-typedef MSARegister Simd128Register;
-
-#define DECLARE_SIMD128_REGISTER(R) \
- constexpr Simd128Register R = Simd128Register::from_code<kMsaCode_##R>();
-SIMD128_REGISTERS(DECLARE_SIMD128_REGISTER)
-#undef DECLARE_SIMD128_REGISTER
-
-const Simd128Register no_msareg = Simd128Register::no_reg();
-
-// Register aliases.
-// cp is assumed to be a callee saved register.
-constexpr Register kRootRegister = s6;
-constexpr Register cp = s7;
-constexpr Register kScratchReg = s3;
-constexpr Register kScratchReg2 = s4;
-constexpr DoubleRegister kScratchDoubleReg = f30;
-constexpr DoubleRegister kDoubleRegZero = f28;
-// Used on mips32r6 for compare operations.
-constexpr DoubleRegister kDoubleCompareReg = f26;
-// MSA zero and scratch regs must have the same numbers as FPU zero and scratch
-constexpr Simd128Register kSimd128RegZero = w28;
-constexpr Simd128Register kSimd128ScratchReg = w30;
-
-// FPU (coprocessor 1) control registers.
-// Currently only FCSR (#31) is implemented.
-struct FPUControlRegister {
- bool is_valid() const { return reg_code == kFCSRRegister; }
- bool is(FPUControlRegister creg) const { return reg_code == creg.reg_code; }
- int code() const {
- DCHECK(is_valid());
- return reg_code;
- }
- int bit() const {
- DCHECK(is_valid());
- return 1 << reg_code;
- }
- void setcode(int f) {
- reg_code = f;
- DCHECK(is_valid());
- }
- // Unfortunately we can't make this private in a struct.
- int reg_code;
-};
-
-constexpr FPUControlRegister no_fpucreg = {kInvalidFPUControlRegister};
-constexpr FPUControlRegister FCSR = {kFCSRRegister};
-
-// MSA control registers
-struct MSAControlRegister {
- bool is_valid() const {
- return (reg_code == kMSAIRRegister) || (reg_code == kMSACSRRegister);
- }
- bool is(MSAControlRegister creg) const { return reg_code == creg.reg_code; }
- int code() const {
- DCHECK(is_valid());
- return reg_code;
- }
- int bit() const {
- DCHECK(is_valid());
- return 1 << reg_code;
- }
- void setcode(int f) {
- reg_code = f;
- DCHECK(is_valid());
- }
- // Unfortunately we can't make this private in a struct.
- int reg_code;
-};
-
-constexpr MSAControlRegister no_msacreg = {kInvalidMSAControlRegister};
-constexpr MSAControlRegister MSAIR = {kMSAIRRegister};
-constexpr MSAControlRegister MSACSR = {kMSACSRRegister};
+// Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls.
+enum BranchDelaySlot { USE_DELAY_SLOT, PROTECT };
// -----------------------------------------------------------------------------
// Machine instruction Operands.
@@ -397,16 +70,12 @@ class Operand {
value_.immediate = static_cast<int32_t>(f.address());
}
V8_INLINE explicit Operand(const char* s);
- V8_INLINE explicit Operand(Object** opp);
- V8_INLINE explicit Operand(Context** cpp);
explicit Operand(Handle<HeapObject> handle);
- V8_INLINE explicit Operand(Smi* value)
- : rm_(no_reg), rmode_(RelocInfo::NONE) {
- value_.immediate = reinterpret_cast<intptr_t>(value);
+ V8_INLINE explicit Operand(Smi value) : rm_(no_reg), rmode_(RelocInfo::NONE) {
+ value_.immediate = static_cast<intptr_t>(value.ptr());
}
static Operand EmbeddedNumber(double number); // Smi or HeapNumber.
- static Operand EmbeddedCode(CodeStub* stub);
static Operand EmbeddedStringConstant(const StringConstantBase* str);
// Register.
@@ -484,15 +153,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// for a detailed comment on the layout (globals.h).
//
// If the provided buffer is nullptr, the assembler allocates and grows its
- // own buffer, and buffer_size determines the initial buffer size. The buffer
- // is owned by the assembler and deallocated upon destruction of the
- // assembler.
- //
- // If the provided buffer is not nullptr, the assembler uses the provided
- // buffer for code generation and assumes its size to be buffer_size. If the
- // buffer is too small, a fatal error occurs. No deallocation of the buffer is
- // done upon destruction of the assembler.
- Assembler(const AssemblerOptions& options, void* buffer, int buffer_size);
+ // own buffer. Otherwise it takes ownership of the provided buffer.
+ explicit Assembler(const AssemblerOptions&,
+ std::unique_ptr<AssemblerBuffer> = {});
+
virtual ~Assembler() { }
// GetCode emits any pending (non-emitted) code and fills the descriptor
@@ -590,13 +254,13 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// of that call in the instruction stream.
inline static Address target_address_from_return_address(Address pc);
- static void QuietNaN(HeapObject* nan);
+ static void QuietNaN(HeapObject nan);
// This sets the branch destination (which gets loaded at the call address).
// This is for calls and branches within generated code. The serializer
// has already deserialized the lui/ori instructions etc.
inline static void deserialization_set_special_target_at(
- Address instruction_payload, Code* code, Address target);
+ Address instruction_payload, Code code, Address target);
// Get the size of the special target encoded at 'instruction_payload'.
inline static int deserialization_special_target_size(
@@ -612,14 +276,22 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Difference between address of current opcode and target address offset,
// when we are generatinga sequence of instructions for long relative PC
- // branches
+ // branches. It is distance between address of the first instruction in
+ // the jump sequence, and the value that ra gets after calling nal().
static constexpr int kLongBranchPCOffset = 3 * kInstrSize;
- // Adjust ra register in branch delay slot of bal instruction so to skip
+ // Adjust ra register in branch delay slot of bal instruction in order to skip
// instructions not needed after optimization of PIC in
// TurboAssembler::BranchAndLink method.
+ static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 3 * kInstrSize;
- static constexpr int kOptimizedBranchAndLinkLongReturnOffset = 4 * kInstrSize;
+ // Offset of target relative address in calls/jumps for builtins. It is
+ // distance between instruction that is placed just after calling
+ // RecordRelocInfo, and the value that ra gets aftr calling nal().
+ static constexpr int kRelativeJumpForBuiltinsOffset = 1 * kInstrSize;
+ // Relative target address of jumps for builtins when we use lui, ori, dsll,
+ // ori sequence when loading address that cannot fit into 32 bits.
+ static constexpr int kRelativeCallForBuiltinsOffset = 3 * kInstrSize;
// Here we are patching the address in the LUI/ORI instruction pair.
// These values are used in the serialization process and must be zero for
@@ -644,10 +316,6 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
static constexpr int kCallTargetAddressOffset = 4 * kInstrSize;
#endif
- // Difference between address of current opcode and value read from pc
- // register.
- static constexpr int kPcLoadDelta = 4;
-
// Max offset for instructions with 16-bit offset field
static constexpr int kMaxBranchOffset = (1 << (18 - 1)) - 1;
@@ -883,8 +551,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void ll(Register rd, const MemOperand& rs);
void sc(Register rd, const MemOperand& rs);
- void llwp(Register rd, Register rt, Register base);
- void scwp(Register rd, Register rt, Register base);
+ void llx(Register rd, const MemOperand& rs);
+ void scx(Register rd, const MemOperand& rs);
// ---------PC-Relative-instructions-----------
@@ -1721,10 +1389,6 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
DISALLOW_IMPLICIT_CONSTRUCTORS(BlockGrowBufferScope);
};
- // Record a comment relocation entry that can be used by a disassembler.
- // Use --code-comments to enable.
- void RecordComment(const char* msg);
-
// Record a deoptimization reason that can be used by a log or cpu profiler.
// Use --trace-deopt to enable.
void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position,
@@ -1733,6 +1397,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
static int RelocateInternalReference(RelocInfo::Mode rmode, Address pc,
intptr_t pc_delta);
+ static void RelocateRelativeReference(RelocInfo::Mode rmode, Address pc,
+ intptr_t pc_delta);
+
// Writes a single byte or word of data in the code stream. Used for
// inline tables, e.g., jump-tables.
void db(uint8_t data);
@@ -1758,9 +1425,11 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
static void instr_at_put(Address pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
}
- Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
+ Instr instr_at(int pos) {
+ return *reinterpret_cast<Instr*>(buffer_start_ + pos);
+ }
void instr_at_put(int pos, Instr instr) {
- *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
+ *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
}
// Check if an instruction is a branch of some kind.
@@ -1782,6 +1451,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
static bool IsJ(Instr instr);
static bool IsLui(Instr instr);
static bool IsOri(Instr instr);
+ static bool IsAddu(Instr instr, Register rd, Register rs, Register rt);
static bool IsJal(Instr instr);
static bool IsJr(Instr instr);
@@ -1836,18 +1506,15 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void CheckTrampolinePool();
- void PatchConstantPoolAccessInstruction(int pc_offset, int offset,
- ConstantPoolEntry::Access access,
- ConstantPoolEntry::Type type) {
- // No embedded constant pool support.
- UNREACHABLE();
- }
-
bool IsPrevInstrCompactBranch() { return prev_instr_compact_branch_; }
static bool IsCompactBranchSupported() {
return IsMipsArchVariant(kMips32r6);
}
+ // Get the code target object for a pc-relative call or jump.
+ V8_INLINE Handle<Code> relative_code_target_object_handle_at(
+ Address pc_) const;
+
inline int UnboundLabelsCount() { return unbound_labels_count_; }
protected:
@@ -1881,6 +1548,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Record reloc info for current pc_.
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+ // Read 32-bit immediate from lui, ori pair that is used to load immediate.
+ static int32_t GetLuiOriImmediate(Instr instr1, Instr instr2);
+
// Block the emission of the trampoline pool before pc_offset.
void BlockTrampolinePoolBefore(int pc_offset) {
if (no_trampoline_pool_before_ < pc_offset)
@@ -1941,6 +1611,12 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
RegList scratch_register_list_;
+ // Generate common instruction sequence.
+ void GenPCRelativeJump(Register tf, Register ts, int32_t imm32,
+ RelocInfo::Mode rmode, BranchDelaySlot bdslot);
+ void GenPCRelativeJumpAndLink(Register t, int32_t imm32,
+ RelocInfo::Mode rmode, BranchDelaySlot bdslot);
+
private:
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512 * MB;
@@ -2129,6 +1805,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void bind_to(Label* L, int pos);
void next(Label* L, bool is_internal);
+ // Patching lui/ori pair which is commonly used for loading constants.
+ static void PatchLuiOriImmediate(Address pc, int32_t imm, Instr instr1,
+ Address offset_lui, Instr instr2,
+ Address offset_ori);
+ void PatchLuiOriImmediate(int pc, int32_t imm, Instr instr1,
+ Address offset_lui, Instr instr2,
+ Address offset_ori);
+
// One trampoline consists of:
// - space for trampoline slots,
// - space for labels.
@@ -2208,6 +1892,8 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
private:
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);
+ int WriteCodeComments();
+
friend class RegExpMacroAssemblerMIPS;
friend class RelocInfo;
friend class BlockTrampolinePoolScope;
@@ -2232,6 +1918,7 @@ class UseScratchRegisterScope {
RegList old_available_;
};
+
} // namespace internal
} // namespace v8