Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef jit_mips_Assembler_mips_h |
michael@0 | 8 | #define jit_mips_Assembler_mips_h |
michael@0 | 9 | |
michael@0 | 10 | #include "mozilla/ArrayUtils.h" |
michael@0 | 11 | #include "mozilla/Attributes.h" |
michael@0 | 12 | #include "mozilla/MathAlgorithms.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "jit/CompactBuffer.h" |
michael@0 | 15 | #include "jit/IonCode.h" |
michael@0 | 16 | #include "jit/IonSpewer.h" |
michael@0 | 17 | #include "jit/mips/Architecture-mips.h" |
michael@0 | 18 | #include "jit/shared/Assembler-shared.h" |
michael@0 | 19 | #include "jit/shared/IonAssemblerBuffer.h" |
michael@0 | 20 | |
michael@0 | 21 | namespace js { |
michael@0 | 22 | namespace jit { |
michael@0 | 23 | |
michael@0 | 24 | static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero }; |
michael@0 | 25 | static MOZ_CONSTEXPR_VAR Register at = { Registers::at }; |
michael@0 | 26 | static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 }; |
michael@0 | 27 | static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 }; |
michael@0 | 28 | static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 }; |
michael@0 | 29 | static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 }; |
michael@0 | 30 | static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 }; |
michael@0 | 31 | static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 }; |
michael@0 | 32 | static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 }; |
michael@0 | 33 | static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 }; |
michael@0 | 34 | static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 }; |
michael@0 | 35 | static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 }; |
michael@0 | 36 | static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 }; |
michael@0 | 37 | static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 }; |
michael@0 | 38 | static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 }; |
michael@0 | 39 | static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 }; |
michael@0 | 40 | static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 }; |
michael@0 | 41 | static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 }; |
michael@0 | 42 | static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 }; |
michael@0 | 43 | static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 }; |
michael@0 | 44 | static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 }; |
michael@0 | 45 | static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 }; |
michael@0 | 46 | static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 }; |
michael@0 | 47 | static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 }; |
michael@0 | 48 | static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 }; |
michael@0 | 49 | static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 }; |
michael@0 | 50 | static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 }; |
michael@0 | 51 | static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 }; |
michael@0 | 52 | static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp }; |
michael@0 | 53 | static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp }; |
michael@0 | 54 | static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp }; |
michael@0 | 55 | static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra }; |
michael@0 | 56 | |
michael@0 | 57 | static MOZ_CONSTEXPR_VAR Register ScratchRegister = at; |
michael@0 | 58 | static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8; |
michael@0 | 59 | |
michael@0 | 60 | // Use arg reg from EnterJIT function as OsrFrameReg. |
michael@0 | 61 | static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3; |
michael@0 | 62 | static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3; |
michael@0 | 63 | static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0; |
michael@0 | 64 | static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1; |
michael@0 | 65 | static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2; |
michael@0 | 66 | static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3; |
michael@0 | 67 | static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4; |
michael@0 | 68 | static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5; |
michael@0 | 69 | |
michael@0 | 70 | static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0; |
michael@0 | 71 | static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1; |
michael@0 | 72 | static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2; |
michael@0 | 73 | static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3; |
michael@0 | 74 | static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin |
michael@0 | 75 | static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin |
michael@0 | 76 | static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 }; |
michael@0 | 77 | static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); |
michael@0 | 78 | |
michael@0 | 79 | class ABIArgGenerator |
michael@0 | 80 | { |
michael@0 | 81 | unsigned usedArgSlots_; |
michael@0 | 82 | bool firstArgFloat; |
michael@0 | 83 | ABIArg current_; |
michael@0 | 84 | |
michael@0 | 85 | public: |
michael@0 | 86 | ABIArgGenerator(); |
michael@0 | 87 | ABIArg next(MIRType argType); |
michael@0 | 88 | ABIArg ¤t() { return current_; } |
michael@0 | 89 | |
michael@0 | 90 | uint32_t stackBytesConsumedSoFar() const { |
michael@0 | 91 | if (usedArgSlots_ <= 4) |
michael@0 | 92 | return 4 * sizeof(intptr_t); |
michael@0 | 93 | |
michael@0 | 94 | return usedArgSlots_ * sizeof(intptr_t); |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | static const Register NonArgReturnVolatileReg0; |
michael@0 | 98 | static const Register NonArgReturnVolatileReg1; |
michael@0 | 99 | }; |
michael@0 | 100 | |
michael@0 | 101 | static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1; |
michael@0 | 102 | |
michael@0 | 103 | static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg }; |
michael@0 | 104 | static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; |
michael@0 | 105 | |
michael@0 | 106 | static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = v1; |
michael@0 | 107 | static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = v0; |
michael@0 | 108 | static MOZ_CONSTEXPR_VAR Register StackPointer = sp; |
michael@0 | 109 | static MOZ_CONSTEXPR_VAR Register FramePointer = fp; |
michael@0 | 110 | static MOZ_CONSTEXPR_VAR Register ReturnReg = v0; |
michael@0 | 111 | static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 }; |
michael@0 | 112 | static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 }; |
michael@0 | 113 | static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 }; |
michael@0 | 114 | |
michael@0 | 115 | static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 }; |
michael@0 | 116 | |
michael@0 | 117 | static MOZ_CONSTEXPR_VAR FloatRegister f0 = {FloatRegisters::f0}; |
michael@0 | 118 | static MOZ_CONSTEXPR_VAR FloatRegister f2 = {FloatRegisters::f2}; |
michael@0 | 119 | static MOZ_CONSTEXPR_VAR FloatRegister f4 = {FloatRegisters::f4}; |
michael@0 | 120 | static MOZ_CONSTEXPR_VAR FloatRegister f6 = {FloatRegisters::f6}; |
michael@0 | 121 | static MOZ_CONSTEXPR_VAR FloatRegister f8 = {FloatRegisters::f8}; |
michael@0 | 122 | static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10}; |
michael@0 | 123 | static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12}; |
michael@0 | 124 | static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14}; |
michael@0 | 125 | static MOZ_CONSTEXPR_VAR FloatRegister f16 = {FloatRegisters::f16}; |
michael@0 | 126 | static MOZ_CONSTEXPR_VAR FloatRegister f18 = {FloatRegisters::f18}; |
michael@0 | 127 | static MOZ_CONSTEXPR_VAR FloatRegister f20 = {FloatRegisters::f20}; |
michael@0 | 128 | static MOZ_CONSTEXPR_VAR FloatRegister f22 = {FloatRegisters::f22}; |
michael@0 | 129 | static MOZ_CONSTEXPR_VAR FloatRegister f24 = {FloatRegisters::f24}; |
michael@0 | 130 | static MOZ_CONSTEXPR_VAR FloatRegister f26 = {FloatRegisters::f26}; |
michael@0 | 131 | static MOZ_CONSTEXPR_VAR FloatRegister f28 = {FloatRegisters::f28}; |
michael@0 | 132 | static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30}; |
michael@0 | 133 | |
michael@0 | 134 | // MIPS CPUs can only load multibyte data that is "naturally" |
michael@0 | 135 | // four-byte-aligned, sp register should be eight-byte-aligned. |
michael@0 | 136 | static const uint32_t StackAlignment = 8; |
michael@0 | 137 | static const uint32_t CodeAlignment = 4; |
michael@0 | 138 | static const bool StackKeptAligned = true; |
michael@0 | 139 | // NativeFrameSize is the size of return adress on stack in AsmJS functions. |
michael@0 | 140 | static const uint32_t NativeFrameSize = sizeof(void*); |
michael@0 | 141 | static const uint32_t AlignmentAtPrologue = 0; |
michael@0 | 142 | static const uint32_t AlignmentMidPrologue = NativeFrameSize; |
michael@0 | 143 | |
michael@0 | 144 | static const Scale ScalePointer = TimesFour; |
michael@0 | 145 | |
michael@0 | 146 | // MIPS instruction types |
michael@0 | 147 | // +---------------------------------------------------------------+ |
michael@0 | 148 | // | 6 | 5 | 5 | 5 | 5 | 6 | |
michael@0 | 149 | // +---------------------------------------------------------------+ |
michael@0 | 150 | // Register type | Opcode | Rs | Rt | Rd | Sa | Function | |
michael@0 | 151 | // +---------------------------------------------------------------+ |
michael@0 | 152 | // | 6 | 5 | 5 | 16 | |
michael@0 | 153 | // +---------------------------------------------------------------+ |
michael@0 | 154 | // Immediate type | Opcode | Rs | Rt | 2's complement constant | |
michael@0 | 155 | // +---------------------------------------------------------------+ |
michael@0 | 156 | // | 6 | 26 | |
michael@0 | 157 | // +---------------------------------------------------------------+ |
michael@0 | 158 | // Jump type | Opcode | jump_target | |
michael@0 | 159 | // +---------------------------------------------------------------+ |
michael@0 | 160 | // 31 bit bit 0 |
michael@0 | 161 | |
michael@0 | 162 | // MIPS instruction encoding constants. |
michael@0 | 163 | static const uint32_t OpcodeShift = 26; |
michael@0 | 164 | static const uint32_t OpcodeBits = 6; |
michael@0 | 165 | static const uint32_t RSShift = 21; |
michael@0 | 166 | static const uint32_t RSBits = 5; |
michael@0 | 167 | static const uint32_t RTShift = 16; |
michael@0 | 168 | static const uint32_t RTBits = 5; |
michael@0 | 169 | static const uint32_t RDShift = 11; |
michael@0 | 170 | static const uint32_t RDBits = 5; |
michael@0 | 171 | static const uint32_t SAShift = 6; |
michael@0 | 172 | static const uint32_t SABits = 5; |
michael@0 | 173 | static const uint32_t FunctionShift = 0; |
michael@0 | 174 | static const uint32_t FunctionBits = 5; |
michael@0 | 175 | static const uint32_t Imm16Shift = 0; |
michael@0 | 176 | static const uint32_t Imm16Bits = 16; |
michael@0 | 177 | static const uint32_t Imm26Shift = 0; |
michael@0 | 178 | static const uint32_t Imm26Bits = 26; |
michael@0 | 179 | static const uint32_t Imm28Shift = 0; |
michael@0 | 180 | static const uint32_t Imm28Bits = 28; |
michael@0 | 181 | static const uint32_t ImmFieldShift = 2; |
michael@0 | 182 | static const uint32_t FccMask = 0x7; |
michael@0 | 183 | static const uint32_t FccShift = 2; |
michael@0 | 184 | |
michael@0 | 185 | |
michael@0 | 186 | // MIPS instruction field bit masks. |
michael@0 | 187 | static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift; |
michael@0 | 188 | static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift; |
michael@0 | 189 | static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift; |
michael@0 | 190 | static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift; |
michael@0 | 191 | static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift; |
michael@0 | 192 | static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift; |
michael@0 | 193 | static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift; |
michael@0 | 194 | static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift; |
michael@0 | 195 | static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift; |
michael@0 | 196 | static const uint32_t RegMask = Registers::Total - 1; |
michael@0 | 197 | static const uint32_t StackAlignmentMask = StackAlignment - 1; |
michael@0 | 198 | |
michael@0 | 199 | static const int32_t MAX_BREAK_CODE = 1024 - 1; |
michael@0 | 200 | |
michael@0 | 201 | class Instruction; |
michael@0 | 202 | class InstReg; |
michael@0 | 203 | class InstImm; |
michael@0 | 204 | class InstJump; |
michael@0 | 205 | class BranchInstBlock; |
michael@0 | 206 | |
michael@0 | 207 | uint32_t RS(Register r); |
michael@0 | 208 | uint32_t RT(Register r); |
michael@0 | 209 | uint32_t RT(uint32_t regCode); |
michael@0 | 210 | uint32_t RT(FloatRegister r); |
michael@0 | 211 | uint32_t RD(Register r); |
michael@0 | 212 | uint32_t RD(FloatRegister r); |
michael@0 | 213 | uint32_t RD(uint32_t regCode); |
michael@0 | 214 | uint32_t SA(uint32_t value); |
michael@0 | 215 | uint32_t SA(FloatRegister r); |
michael@0 | 216 | |
michael@0 | 217 | Register toRS (Instruction &i); |
michael@0 | 218 | Register toRT (Instruction &i); |
michael@0 | 219 | Register toRD (Instruction &i); |
michael@0 | 220 | Register toR (Instruction &i); |
michael@0 | 221 | |
michael@0 | 222 | // MIPS enums for instruction fields |
michael@0 | 223 | enum Opcode { |
michael@0 | 224 | op_special = 0 << OpcodeShift, |
michael@0 | 225 | op_regimm = 1 << OpcodeShift, |
michael@0 | 226 | |
michael@0 | 227 | op_j = 2 << OpcodeShift, |
michael@0 | 228 | op_jal = 3 << OpcodeShift, |
michael@0 | 229 | op_beq = 4 << OpcodeShift, |
michael@0 | 230 | op_bne = 5 << OpcodeShift, |
michael@0 | 231 | op_blez = 6 << OpcodeShift, |
michael@0 | 232 | op_bgtz = 7 << OpcodeShift, |
michael@0 | 233 | |
michael@0 | 234 | op_addi = 8 << OpcodeShift, |
michael@0 | 235 | op_addiu = 9 << OpcodeShift, |
michael@0 | 236 | op_slti = 10 << OpcodeShift, |
michael@0 | 237 | op_sltiu = 11 << OpcodeShift, |
michael@0 | 238 | op_andi = 12 << OpcodeShift, |
michael@0 | 239 | op_ori = 13 << OpcodeShift, |
michael@0 | 240 | op_xori = 14 << OpcodeShift, |
michael@0 | 241 | op_lui = 15 << OpcodeShift, |
michael@0 | 242 | |
michael@0 | 243 | op_cop1 = 17 << OpcodeShift, |
michael@0 | 244 | op_cop1x = 19 << OpcodeShift, |
michael@0 | 245 | |
michael@0 | 246 | op_beql = 20 << OpcodeShift, |
michael@0 | 247 | op_bnel = 21 << OpcodeShift, |
michael@0 | 248 | op_blezl = 22 << OpcodeShift, |
michael@0 | 249 | op_bgtzl = 23 << OpcodeShift, |
michael@0 | 250 | |
michael@0 | 251 | op_special2 = 28 << OpcodeShift, |
michael@0 | 252 | op_special3 = 31 << OpcodeShift, |
michael@0 | 253 | |
michael@0 | 254 | op_lb = 32 << OpcodeShift, |
michael@0 | 255 | op_lh = 33 << OpcodeShift, |
michael@0 | 256 | op_lwl = 34 << OpcodeShift, |
michael@0 | 257 | op_lw = 35 << OpcodeShift, |
michael@0 | 258 | op_lbu = 36 << OpcodeShift, |
michael@0 | 259 | op_lhu = 37 << OpcodeShift, |
michael@0 | 260 | op_lwr = 38 << OpcodeShift, |
michael@0 | 261 | op_sb = 40 << OpcodeShift, |
michael@0 | 262 | op_sh = 41 << OpcodeShift, |
michael@0 | 263 | op_swl = 42 << OpcodeShift, |
michael@0 | 264 | op_sw = 43 << OpcodeShift, |
michael@0 | 265 | op_swr = 46 << OpcodeShift, |
michael@0 | 266 | |
michael@0 | 267 | op_lwc1 = 49 << OpcodeShift, |
michael@0 | 268 | op_ldc1 = 53 << OpcodeShift, |
michael@0 | 269 | |
michael@0 | 270 | op_swc1 = 57 << OpcodeShift, |
michael@0 | 271 | op_sdc1 = 61 << OpcodeShift |
michael@0 | 272 | }; |
michael@0 | 273 | |
michael@0 | 274 | enum RSField { |
michael@0 | 275 | rs_zero = 0 << RSShift, |
michael@0 | 276 | // cop1 encoding of RS field. |
michael@0 | 277 | rs_mfc1 = 0 << RSShift, |
michael@0 | 278 | rs_one = 1 << RSShift, |
michael@0 | 279 | rs_cfc1 = 2 << RSShift, |
michael@0 | 280 | rs_mfhc1 = 3 << RSShift, |
michael@0 | 281 | rs_mtc1 = 4 << RSShift, |
michael@0 | 282 | rs_ctc1 = 6 << RSShift, |
michael@0 | 283 | rs_mthc1 = 7 << RSShift, |
michael@0 | 284 | rs_bc1 = 8 << RSShift, |
michael@0 | 285 | rs_s = 16 << RSShift, |
michael@0 | 286 | rs_d = 17 << RSShift, |
michael@0 | 287 | rs_w = 20 << RSShift, |
michael@0 | 288 | rs_ps = 22 << RSShift |
michael@0 | 289 | }; |
michael@0 | 290 | |
michael@0 | 291 | enum RTField { |
michael@0 | 292 | rt_zero = 0 << RTShift, |
michael@0 | 293 | // regimm encoding of RT field. |
michael@0 | 294 | rt_bltz = 0 << RTShift, |
michael@0 | 295 | rt_bgez = 1 << RTShift, |
michael@0 | 296 | rt_bltzal = 16 << RTShift, |
michael@0 | 297 | rt_bgezal = 17 << RTShift |
michael@0 | 298 | }; |
michael@0 | 299 | |
michael@0 | 300 | enum FunctionField { |
michael@0 | 301 | // special encoding of function field. |
michael@0 | 302 | ff_sll = 0, |
michael@0 | 303 | ff_movci = 1, |
michael@0 | 304 | ff_srl = 2, |
michael@0 | 305 | ff_sra = 3, |
michael@0 | 306 | ff_sllv = 4, |
michael@0 | 307 | ff_srlv = 6, |
michael@0 | 308 | ff_srav = 7, |
michael@0 | 309 | |
michael@0 | 310 | ff_jr = 8, |
michael@0 | 311 | ff_jalr = 9, |
michael@0 | 312 | ff_movz = 10, |
michael@0 | 313 | ff_movn = 11, |
michael@0 | 314 | ff_break = 13, |
michael@0 | 315 | |
michael@0 | 316 | ff_mfhi = 16, |
michael@0 | 317 | ff_mflo = 18, |
michael@0 | 318 | |
michael@0 | 319 | ff_mult = 24, |
michael@0 | 320 | ff_multu = 25, |
michael@0 | 321 | ff_div = 26, |
michael@0 | 322 | ff_divu = 27, |
michael@0 | 323 | |
michael@0 | 324 | ff_add = 32, |
michael@0 | 325 | ff_addu = 33, |
michael@0 | 326 | ff_sub = 34, |
michael@0 | 327 | ff_subu = 35, |
michael@0 | 328 | ff_and = 36, |
michael@0 | 329 | ff_or = 37, |
michael@0 | 330 | ff_xor = 38, |
michael@0 | 331 | ff_nor = 39, |
michael@0 | 332 | |
michael@0 | 333 | ff_slt = 42, |
michael@0 | 334 | ff_sltu = 43, |
michael@0 | 335 | |
michael@0 | 336 | // special2 encoding of function field. |
michael@0 | 337 | ff_mul = 2, |
michael@0 | 338 | ff_clz = 32, |
michael@0 | 339 | ff_clo = 33, |
michael@0 | 340 | |
michael@0 | 341 | // special3 encoding of function field. |
michael@0 | 342 | ff_ext = 0, |
michael@0 | 343 | ff_ins = 4, |
michael@0 | 344 | |
michael@0 | 345 | // cop1 encoding of function field. |
michael@0 | 346 | ff_add_fmt = 0, |
michael@0 | 347 | ff_sub_fmt = 1, |
michael@0 | 348 | ff_mul_fmt = 2, |
michael@0 | 349 | ff_div_fmt = 3, |
michael@0 | 350 | ff_sqrt_fmt = 4, |
michael@0 | 351 | ff_abs_fmt = 5, |
michael@0 | 352 | ff_mov_fmt = 6, |
michael@0 | 353 | ff_neg_fmt = 7, |
michael@0 | 354 | |
michael@0 | 355 | ff_round_w_fmt = 12, |
michael@0 | 356 | ff_trunc_w_fmt = 13, |
michael@0 | 357 | ff_ceil_w_fmt = 14, |
michael@0 | 358 | ff_floor_w_fmt = 15, |
michael@0 | 359 | |
michael@0 | 360 | ff_cvt_s_fmt = 32, |
michael@0 | 361 | ff_cvt_d_fmt = 33, |
michael@0 | 362 | ff_cvt_w_fmt = 36, |
michael@0 | 363 | |
michael@0 | 364 | ff_c_f_fmt = 48, |
michael@0 | 365 | ff_c_un_fmt = 49, |
michael@0 | 366 | ff_c_eq_fmt = 50, |
michael@0 | 367 | ff_c_ueq_fmt = 51, |
michael@0 | 368 | ff_c_olt_fmt = 52, |
michael@0 | 369 | ff_c_ult_fmt = 53, |
michael@0 | 370 | ff_c_ole_fmt = 54, |
michael@0 | 371 | ff_c_ule_fmt = 55, |
michael@0 | 372 | }; |
michael@0 | 373 | |
michael@0 | 374 | class MacroAssemblerMIPS; |
michael@0 | 375 | class Operand; |
michael@0 | 376 | |
michael@0 | 377 | // A BOffImm16 is a 16 bit immediate that is used for branches. |
michael@0 | 378 | class BOffImm16 |
michael@0 | 379 | { |
michael@0 | 380 | uint32_t data; |
michael@0 | 381 | |
michael@0 | 382 | public: |
michael@0 | 383 | uint32_t encode() { |
michael@0 | 384 | JS_ASSERT(!isInvalid()); |
michael@0 | 385 | return data; |
michael@0 | 386 | } |
michael@0 | 387 | int32_t decode() { |
michael@0 | 388 | JS_ASSERT(!isInvalid()); |
michael@0 | 389 | return (int32_t(data << 18) >> 16) + 4; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | explicit BOffImm16(int offset) |
michael@0 | 393 | : data ((offset - 4) >> 2 & Imm16Mask) |
michael@0 | 394 | { |
michael@0 | 395 | JS_ASSERT((offset & 0x3) == 0); |
michael@0 | 396 | JS_ASSERT(isInRange(offset)); |
michael@0 | 397 | } |
michael@0 | 398 | static bool isInRange(int offset) { |
michael@0 | 399 | if ((offset - 4) < (INT16_MIN << 2)) |
michael@0 | 400 | return false; |
michael@0 | 401 | if ((offset - 4) > (INT16_MAX << 2)) |
michael@0 | 402 | return false; |
michael@0 | 403 | return true; |
michael@0 | 404 | } |
michael@0 | 405 | static const uint32_t INVALID = 0x00020000; |
michael@0 | 406 | BOffImm16() |
michael@0 | 407 | : data(INVALID) |
michael@0 | 408 | { } |
michael@0 | 409 | |
michael@0 | 410 | bool isInvalid() { |
michael@0 | 411 | return data == INVALID; |
michael@0 | 412 | } |
michael@0 | 413 | Instruction *getDest(Instruction *src); |
michael@0 | 414 | |
michael@0 | 415 | BOffImm16(InstImm inst); |
michael@0 | 416 | }; |
michael@0 | 417 | |
michael@0 | 418 | // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps. |
michael@0 | 419 | class JOffImm26 |
michael@0 | 420 | { |
michael@0 | 421 | uint32_t data; |
michael@0 | 422 | |
michael@0 | 423 | public: |
michael@0 | 424 | uint32_t encode() { |
michael@0 | 425 | JS_ASSERT(!isInvalid()); |
michael@0 | 426 | return data; |
michael@0 | 427 | } |
michael@0 | 428 | int32_t decode() { |
michael@0 | 429 | JS_ASSERT(!isInvalid()); |
michael@0 | 430 | return (int32_t(data << 8) >> 6) + 4; |
michael@0 | 431 | } |
michael@0 | 432 | |
michael@0 | 433 | explicit JOffImm26(int offset) |
michael@0 | 434 | : data ((offset - 4) >> 2 & Imm26Mask) |
michael@0 | 435 | { |
michael@0 | 436 | JS_ASSERT((offset & 0x3) == 0); |
michael@0 | 437 | JS_ASSERT(isInRange(offset)); |
michael@0 | 438 | } |
michael@0 | 439 | static bool isInRange(int offset) { |
michael@0 | 440 | if ((offset - 4) < -536870912) |
michael@0 | 441 | return false; |
michael@0 | 442 | if ((offset - 4) > 536870908) |
michael@0 | 443 | return false; |
michael@0 | 444 | return true; |
michael@0 | 445 | } |
michael@0 | 446 | static const uint32_t INVALID = 0x20000000; |
michael@0 | 447 | JOffImm26() |
michael@0 | 448 | : data(INVALID) |
michael@0 | 449 | { } |
michael@0 | 450 | |
michael@0 | 451 | bool isInvalid() { |
michael@0 | 452 | return data == INVALID; |
michael@0 | 453 | } |
michael@0 | 454 | Instruction *getDest(Instruction *src); |
michael@0 | 455 | |
michael@0 | 456 | }; |
michael@0 | 457 | |
michael@0 | 458 | class Imm16 |
michael@0 | 459 | { |
michael@0 | 460 | uint16_t value; |
michael@0 | 461 | |
michael@0 | 462 | public: |
michael@0 | 463 | Imm16(); |
michael@0 | 464 | Imm16(uint32_t imm) |
michael@0 | 465 | : value(imm) |
michael@0 | 466 | { } |
michael@0 | 467 | uint32_t encode() { |
michael@0 | 468 | return value; |
michael@0 | 469 | } |
michael@0 | 470 | int32_t decodeSigned() { |
michael@0 | 471 | return value; |
michael@0 | 472 | } |
michael@0 | 473 | uint32_t decodeUnsigned() { |
michael@0 | 474 | return value; |
michael@0 | 475 | } |
michael@0 | 476 | static bool isInSignedRange(int32_t imm) { |
michael@0 | 477 | return imm >= INT16_MIN && imm <= INT16_MAX; |
michael@0 | 478 | } |
michael@0 | 479 | static bool isInUnsignedRange(uint32_t imm) { |
michael@0 | 480 | return imm <= UINT16_MAX ; |
michael@0 | 481 | } |
michael@0 | 482 | static Imm16 lower (Imm32 imm) { |
michael@0 | 483 | return Imm16(imm.value & 0xffff); |
michael@0 | 484 | } |
michael@0 | 485 | static Imm16 upper (Imm32 imm) { |
michael@0 | 486 | return Imm16((imm.value >> 16) & 0xffff); |
michael@0 | 487 | } |
michael@0 | 488 | }; |
michael@0 | 489 | |
michael@0 | 490 | class Operand |
michael@0 | 491 | { |
michael@0 | 492 | public: |
michael@0 | 493 | enum Tag { |
michael@0 | 494 | REG, |
michael@0 | 495 | FREG, |
michael@0 | 496 | MEM |
michael@0 | 497 | }; |
michael@0 | 498 | |
michael@0 | 499 | private: |
michael@0 | 500 | Tag tag : 3; |
michael@0 | 501 | uint32_t reg : 5; |
michael@0 | 502 | int32_t offset; |
michael@0 | 503 | |
michael@0 | 504 | public: |
michael@0 | 505 | Operand (Register reg_) |
michael@0 | 506 | : tag(REG), reg(reg_.code()) |
michael@0 | 507 | { } |
michael@0 | 508 | |
michael@0 | 509 | Operand (FloatRegister freg) |
michael@0 | 510 | : tag(FREG), reg(freg.code()) |
michael@0 | 511 | { } |
michael@0 | 512 | |
michael@0 | 513 | Operand (Register base, Imm32 off) |
michael@0 | 514 | : tag(MEM), reg(base.code()), offset(off.value) |
michael@0 | 515 | { } |
michael@0 | 516 | |
michael@0 | 517 | Operand (Register base, int32_t off) |
michael@0 | 518 | : tag(MEM), reg(base.code()), offset(off) |
michael@0 | 519 | { } |
michael@0 | 520 | |
michael@0 | 521 | Operand (const Address &addr) |
michael@0 | 522 | : tag(MEM), reg(addr.base.code()), offset(addr.offset) |
michael@0 | 523 | { } |
michael@0 | 524 | |
michael@0 | 525 | Tag getTag() const { |
michael@0 | 526 | return tag; |
michael@0 | 527 | } |
michael@0 | 528 | |
michael@0 | 529 | Register toReg() const { |
michael@0 | 530 | JS_ASSERT(tag == REG); |
michael@0 | 531 | return Register::FromCode(reg); |
michael@0 | 532 | } |
michael@0 | 533 | |
michael@0 | 534 | FloatRegister toFReg() const { |
michael@0 | 535 | JS_ASSERT(tag == FREG); |
michael@0 | 536 | return FloatRegister::FromCode(reg); |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | void toAddr(Register *r, Imm32 *dest) const { |
michael@0 | 540 | JS_ASSERT(tag == MEM); |
michael@0 | 541 | *r = Register::FromCode(reg); |
michael@0 | 542 | *dest = Imm32(offset); |
michael@0 | 543 | } |
michael@0 | 544 | Address toAddress() const { |
michael@0 | 545 | JS_ASSERT(tag == MEM); |
michael@0 | 546 | return Address(Register::FromCode(reg), offset); |
michael@0 | 547 | } |
michael@0 | 548 | int32_t disp() const { |
michael@0 | 549 | JS_ASSERT(tag == MEM); |
michael@0 | 550 | return offset; |
michael@0 | 551 | } |
michael@0 | 552 | |
michael@0 | 553 | int32_t base() const { |
michael@0 | 554 | JS_ASSERT(tag == MEM); |
michael@0 | 555 | return reg; |
michael@0 | 556 | } |
michael@0 | 557 | Register baseReg() const { |
michael@0 | 558 | JS_ASSERT(tag == MEM); |
michael@0 | 559 | return Register::FromCode(reg); |
michael@0 | 560 | } |
michael@0 | 561 | }; |
michael@0 | 562 | |
michael@0 | 563 | void |
michael@0 | 564 | PatchJump(CodeLocationJump &jump_, CodeLocationLabel label); |
michael@0 | 565 | class Assembler; |
michael@0 | 566 | typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer; |
michael@0 | 567 | |
michael@0 | 568 | class Assembler : public AssemblerShared |
michael@0 | 569 | { |
michael@0 | 570 | public: |
michael@0 | 571 | |
michael@0 | 572 | enum Condition { |
michael@0 | 573 | Equal, |
michael@0 | 574 | NotEqual, |
michael@0 | 575 | Above, |
michael@0 | 576 | AboveOrEqual, |
michael@0 | 577 | Below, |
michael@0 | 578 | BelowOrEqual, |
michael@0 | 579 | GreaterThan, |
michael@0 | 580 | GreaterThanOrEqual, |
michael@0 | 581 | LessThan, |
michael@0 | 582 | LessThanOrEqual, |
michael@0 | 583 | Overflow, |
michael@0 | 584 | Signed, |
michael@0 | 585 | NotSigned, |
michael@0 | 586 | Zero, |
michael@0 | 587 | NonZero, |
michael@0 | 588 | Always, |
michael@0 | 589 | }; |
michael@0 | 590 | |
michael@0 | 591 | enum DoubleCondition { |
michael@0 | 592 | // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. |
michael@0 | 593 | DoubleOrdered, |
michael@0 | 594 | DoubleEqual, |
michael@0 | 595 | DoubleNotEqual, |
michael@0 | 596 | DoubleGreaterThan, |
michael@0 | 597 | DoubleGreaterThanOrEqual, |
michael@0 | 598 | DoubleLessThan, |
michael@0 | 599 | DoubleLessThanOrEqual, |
michael@0 | 600 | // If either operand is NaN, these conditions always evaluate to true. |
michael@0 | 601 | DoubleUnordered, |
michael@0 | 602 | DoubleEqualOrUnordered, |
michael@0 | 603 | DoubleNotEqualOrUnordered, |
michael@0 | 604 | DoubleGreaterThanOrUnordered, |
michael@0 | 605 | DoubleGreaterThanOrEqualOrUnordered, |
michael@0 | 606 | DoubleLessThanOrUnordered, |
michael@0 | 607 | DoubleLessThanOrEqualOrUnordered |
michael@0 | 608 | }; |
michael@0 | 609 | |
michael@0 | 610 | enum FPConditionBit { |
michael@0 | 611 | FCC0 = 0, |
michael@0 | 612 | FCC1, |
michael@0 | 613 | FCC2, |
michael@0 | 614 | FCC3, |
michael@0 | 615 | FCC4, |
michael@0 | 616 | FCC5, |
michael@0 | 617 | FCC6, |
michael@0 | 618 | FCC7 |
michael@0 | 619 | }; |
michael@0 | 620 | |
michael@0 | 621 | enum FloatFormat { |
michael@0 | 622 | SingleFloat, |
michael@0 | 623 | DoubleFloat |
michael@0 | 624 | }; |
michael@0 | 625 | |
michael@0 | 626 | enum JumpOrCall { |
michael@0 | 627 | BranchIsJump, |
michael@0 | 628 | BranchIsCall |
michael@0 | 629 | }; |
michael@0 | 630 | |
michael@0 | 631 | enum FloatTestKind { |
michael@0 | 632 | TestForTrue, |
michael@0 | 633 | TestForFalse |
michael@0 | 634 | }; |
michael@0 | 635 | |
michael@0 | 636 | // :( this should be protected, but since CodeGenerator |
michael@0 | 637 | // wants to use it, It needs to go out here :( |
michael@0 | 638 | |
michael@0 | 639 | BufferOffset nextOffset() { |
michael@0 | 640 | return m_buffer.nextOffset(); |
michael@0 | 641 | } |
michael@0 | 642 | |
michael@0 | 643 | protected: |
michael@0 | 644 | Instruction * editSrc (BufferOffset bo) { |
michael@0 | 645 | return m_buffer.getInst(bo); |
michael@0 | 646 | } |
michael@0 | 647 | public: |
michael@0 | 648 | uint32_t actualOffset(uint32_t) const; |
michael@0 | 649 | uint32_t actualIndex(uint32_t) const; |
michael@0 | 650 | static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index); |
michael@0 | 651 | protected: |
michael@0 | 652 | |
michael@0 | 653 | // structure for fixing up pc-relative loads/jumps when a the machine code |
michael@0 | 654 | // gets moved (executable copy, gc, etc.) |
michael@0 | 655 | struct RelativePatch |
michael@0 | 656 | { |
michael@0 | 657 | // the offset within the code buffer where the value is loaded that |
michael@0 | 658 | // we want to fix-up |
michael@0 | 659 | BufferOffset offset; |
michael@0 | 660 | void *target; |
michael@0 | 661 | Relocation::Kind kind; |
michael@0 | 662 | |
michael@0 | 663 | RelativePatch(BufferOffset offset, void *target, Relocation::Kind kind) |
michael@0 | 664 | : offset(offset), |
michael@0 | 665 | target(target), |
michael@0 | 666 | kind(kind) |
michael@0 | 667 | { } |
michael@0 | 668 | }; |
michael@0 | 669 | |
michael@0 | 670 | js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_; |
michael@0 | 671 | js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_; |
michael@0 | 672 | js::Vector<uint32_t, 8, SystemAllocPolicy> longJumps_; |
michael@0 | 673 | |
michael@0 | 674 | CompactBufferWriter jumpRelocations_; |
michael@0 | 675 | CompactBufferWriter dataRelocations_; |
michael@0 | 676 | CompactBufferWriter relocations_; |
michael@0 | 677 | CompactBufferWriter preBarriers_; |
michael@0 | 678 | |
michael@0 | 679 | bool enoughMemory_; |
michael@0 | 680 | |
michael@0 | 681 | MIPSBuffer m_buffer; |
michael@0 | 682 | |
michael@0 | 683 | public: |
michael@0 | 684 | Assembler() |
michael@0 | 685 | : enoughMemory_(true), |
michael@0 | 686 | m_buffer(), |
michael@0 | 687 | isFinished(false) |
michael@0 | 688 | { } |
michael@0 | 689 | |
michael@0 | 690 | static Condition InvertCondition(Condition cond); |
michael@0 | 691 | static DoubleCondition InvertCondition(DoubleCondition cond); |
michael@0 | 692 | |
michael@0 | 693 | // MacroAssemblers hold onto gcthings, so they are traced by the GC. |
michael@0 | 694 | void trace(JSTracer *trc); |
michael@0 | 695 | void writeRelocation(BufferOffset src) { |
michael@0 | 696 | jumpRelocations_.writeUnsigned(src.getOffset()); |
michael@0 | 697 | } |
michael@0 | 698 | |
michael@0 | 699 | // As opposed to x86/x64 version, the data relocation has to be executed |
michael@0 | 700 | // before to recover the pointer, and not after. |
michael@0 | 701 | void writeDataRelocation(const ImmGCPtr &ptr) { |
michael@0 | 702 | if (ptr.value) |
michael@0 | 703 | dataRelocations_.writeUnsigned(nextOffset().getOffset()); |
michael@0 | 704 | } |
michael@0 | 705 | void writePrebarrierOffset(CodeOffsetLabel label) { |
michael@0 | 706 | preBarriers_.writeUnsigned(label.offset()); |
michael@0 | 707 | } |
michael@0 | 708 | |
michael@0 | 709 | public: |
michael@0 | 710 | static uintptr_t getPointer(uint8_t *); |
michael@0 | 711 | |
michael@0 | 712 | bool oom() const; |
michael@0 | 713 | |
michael@0 | 714 | void setPrinter(Sprinter *sp) { |
michael@0 | 715 | } |
michael@0 | 716 | |
michael@0 | 717 | private: |
michael@0 | 718 | bool isFinished; |
michael@0 | 719 | public: |
michael@0 | 720 | void finish(); |
michael@0 | 721 | void executableCopy(void *buffer); |
michael@0 | 722 | void copyJumpRelocationTable(uint8_t *dest); |
michael@0 | 723 | void copyDataRelocationTable(uint8_t *dest); |
michael@0 | 724 | void copyPreBarrierTable(uint8_t *dest); |
michael@0 | 725 | |
michael@0 | 726 | bool addCodeLabel(CodeLabel label); |
michael@0 | 727 | size_t numCodeLabels() const { |
michael@0 | 728 | return codeLabels_.length(); |
michael@0 | 729 | } |
michael@0 | 730 | CodeLabel codeLabel(size_t i) { |
michael@0 | 731 | return codeLabels_[i]; |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | // Size of the instruction stream, in bytes. |
michael@0 | 735 | size_t size() const; |
michael@0 | 736 | // Size of the jump relocation table, in bytes. |
michael@0 | 737 | size_t jumpRelocationTableBytes() const; |
michael@0 | 738 | size_t dataRelocationTableBytes() const; |
michael@0 | 739 | size_t preBarrierTableBytes() const; |
michael@0 | 740 | |
michael@0 | 741 | // Size of the data table, in bytes. |
michael@0 | 742 | size_t bytesNeeded() const; |
michael@0 | 743 | |
michael@0 | 744 | // Write a blob of binary into the instruction stream *OR* |
michael@0 | 745 | // into a destination address. If dest is nullptr (the default), then the |
michael@0 | 746 | // instruction gets written into the instruction stream. If dest is not null |
michael@0 | 747 | // it is interpreted as a pointer to the location that we want the |
michael@0 | 748 | // instruction to be written. |
michael@0 | 749 | BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr); |
michael@0 | 750 | // A static variant for the cases where we don't want to have an assembler |
michael@0 | 751 | // object at all. Normally, you would use the dummy (nullptr) object. |
michael@0 | 752 | static void writeInstStatic(uint32_t x, uint32_t *dest); |
michael@0 | 753 | |
michael@0 | 754 | public: |
michael@0 | 755 | BufferOffset align(int alignment); |
michael@0 | 756 | BufferOffset as_nop(); |
michael@0 | 757 | |
michael@0 | 758 | // Branch and jump instructions |
michael@0 | 759 | BufferOffset as_bal(BOffImm16 off); |
michael@0 | 760 | |
michael@0 | 761 | InstImm getBranchCode(JumpOrCall jumpOrCall); |
michael@0 | 762 | InstImm getBranchCode(Register s, Register t, Condition c); |
michael@0 | 763 | InstImm getBranchCode(Register s, Condition c); |
michael@0 | 764 | InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc); |
michael@0 | 765 | |
michael@0 | 766 | BufferOffset as_j(JOffImm26 off); |
michael@0 | 767 | BufferOffset as_jal(JOffImm26 off); |
michael@0 | 768 | |
michael@0 | 769 | BufferOffset as_jr(Register rs); |
michael@0 | 770 | BufferOffset as_jalr(Register rs); |
michael@0 | 771 | |
michael@0 | 772 | // Arithmetic instructions |
michael@0 | 773 | BufferOffset as_addu(Register rd, Register rs, Register rt); |
michael@0 | 774 | BufferOffset as_addiu(Register rd, Register rs, int32_t j); |
michael@0 | 775 | BufferOffset as_subu(Register rd, Register rs, Register rt); |
michael@0 | 776 | BufferOffset as_mult(Register rs, Register rt); |
michael@0 | 777 | BufferOffset as_multu(Register rs, Register rt); |
michael@0 | 778 | BufferOffset as_div(Register rs, Register rt); |
michael@0 | 779 | BufferOffset as_divu(Register rs, Register rt); |
michael@0 | 780 | BufferOffset as_mul(Register rd, Register rs, Register rt); |
michael@0 | 781 | |
michael@0 | 782 | // Logical instructions |
michael@0 | 783 | BufferOffset as_and(Register rd, Register rs, Register rt); |
michael@0 | 784 | BufferOffset as_or(Register rd, Register rs, Register rt); |
michael@0 | 785 | BufferOffset as_xor(Register rd, Register rs, Register rt); |
michael@0 | 786 | BufferOffset as_nor(Register rd, Register rs, Register rt); |
michael@0 | 787 | |
michael@0 | 788 | BufferOffset as_andi(Register rd, Register rs, int32_t j); |
michael@0 | 789 | BufferOffset as_ori(Register rd, Register rs, int32_t j); |
michael@0 | 790 | BufferOffset as_xori(Register rd, Register rs, int32_t j); |
michael@0 | 791 | BufferOffset as_lui(Register rd, int32_t j); |
michael@0 | 792 | |
michael@0 | 793 | // Shift instructions |
michael@0 | 794 | // as_sll(zero, zero, x) instructions are reserved as nop |
michael@0 | 795 | BufferOffset as_sll(Register rd, Register rt, uint16_t sa); |
michael@0 | 796 | BufferOffset as_sllv(Register rd, Register rt, Register rs); |
michael@0 | 797 | BufferOffset as_srl(Register rd, Register rt, uint16_t sa); |
michael@0 | 798 | BufferOffset as_srlv(Register rd, Register rt, Register rs); |
michael@0 | 799 | BufferOffset as_sra(Register rd, Register rt, uint16_t sa); |
michael@0 | 800 | BufferOffset as_srav(Register rd, Register rt, Register rs); |
michael@0 | 801 | BufferOffset as_rotr(Register rd, Register rt, uint16_t sa); |
michael@0 | 802 | BufferOffset as_rotrv(Register rd, Register rt, Register rs); |
michael@0 | 803 | |
michael@0 | 804 | // Load and store instructions |
michael@0 | 805 | BufferOffset as_lb(Register rd, Register rs, int16_t off); |
michael@0 | 806 | BufferOffset as_lbu(Register rd, Register rs, int16_t off); |
michael@0 | 807 | BufferOffset as_lh(Register rd, Register rs, int16_t off); |
michael@0 | 808 | BufferOffset as_lhu(Register rd, Register rs, int16_t off); |
michael@0 | 809 | BufferOffset as_lw(Register rd, Register rs, int16_t off); |
michael@0 | 810 | BufferOffset as_lwl(Register rd, Register rs, int16_t off); |
michael@0 | 811 | BufferOffset as_lwr(Register rd, Register rs, int16_t off); |
michael@0 | 812 | BufferOffset as_sb(Register rd, Register rs, int16_t off); |
michael@0 | 813 | BufferOffset as_sh(Register rd, Register rs, int16_t off); |
michael@0 | 814 | BufferOffset as_sw(Register rd, Register rs, int16_t off); |
michael@0 | 815 | BufferOffset as_swl(Register rd, Register rs, int16_t off); |
michael@0 | 816 | BufferOffset as_swr(Register rd, Register rs, int16_t off); |
michael@0 | 817 | |
michael@0 | 818 | // Move from HI/LO register. |
michael@0 | 819 | BufferOffset as_mfhi(Register rd); |
michael@0 | 820 | BufferOffset as_mflo(Register rd); |
michael@0 | 821 | |
michael@0 | 822 | // Set on less than. |
michael@0 | 823 | BufferOffset as_slt(Register rd, Register rs, Register rt); |
michael@0 | 824 | BufferOffset as_sltu(Register rd, Register rs, Register rt); |
michael@0 | 825 | BufferOffset as_slti(Register rd, Register rs, int32_t j); |
michael@0 | 826 | BufferOffset as_sltiu(Register rd, Register rs, uint32_t j); |
michael@0 | 827 | |
michael@0 | 828 | // Conditional move. |
michael@0 | 829 | BufferOffset as_movz(Register rd, Register rs, Register rt); |
michael@0 | 830 | BufferOffset as_movn(Register rd, Register rs, Register rt); |
michael@0 | 831 | BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0); |
michael@0 | 832 | BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0); |
michael@0 | 833 | |
michael@0 | 834 | // Bit twiddling. |
michael@0 | 835 | BufferOffset as_clz(Register rd, Register rs, Register rt = Register::FromCode(0)); |
michael@0 | 836 | BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size); |
michael@0 | 837 | BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size); |
michael@0 | 838 | |
michael@0 | 839 | // FP instructions |
michael@0 | 840 | |
michael@0 | 841 | // Use these two functions only when you are sure address is aligned. |
michael@0 | 842 | // Otherwise, use ma_ld and ma_sd. |
michael@0 | 843 | BufferOffset as_ld(FloatRegister fd, Register base, int32_t off); |
michael@0 | 844 | BufferOffset as_sd(FloatRegister fd, Register base, int32_t off); |
michael@0 | 845 | |
michael@0 | 846 | BufferOffset as_ls(FloatRegister fd, Register base, int32_t off); |
michael@0 | 847 | BufferOffset as_ss(FloatRegister fd, Register base, int32_t off); |
michael@0 | 848 | |
michael@0 | 849 | BufferOffset as_movs(FloatRegister fd, FloatRegister fs); |
michael@0 | 850 | BufferOffset as_movd(FloatRegister fd, FloatRegister fs); |
michael@0 | 851 | |
michael@0 | 852 | BufferOffset as_mtc1(Register rt, FloatRegister fs); |
michael@0 | 853 | BufferOffset as_mfc1(Register rt, FloatRegister fs); |
michael@0 | 854 | |
michael@0 | 855 | protected: |
michael@0 | 856 | // This is used to access the odd regiter form the pair of single |
michael@0 | 857 | // precision registers that make one double register. |
michael@0 | 858 | FloatRegister getOddPair(FloatRegister reg) { |
michael@0 | 859 | JS_ASSERT(reg.code() % 2 == 0); |
michael@0 | 860 | return FloatRegister::FromCode(reg.code() + 1); |
michael@0 | 861 | } |
michael@0 | 862 | |
michael@0 | 863 | public: |
michael@0 | 864 | // FP convert instructions |
michael@0 | 865 | BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs); |
michael@0 | 866 | BufferOffset as_floorws(FloatRegister fd, FloatRegister fs); |
michael@0 | 867 | BufferOffset as_roundws(FloatRegister fd, FloatRegister fs); |
michael@0 | 868 | BufferOffset as_truncws(FloatRegister fd, FloatRegister fs); |
michael@0 | 869 | |
michael@0 | 870 | BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs); |
michael@0 | 871 | BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs); |
michael@0 | 872 | BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs); |
michael@0 | 873 | BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs); |
michael@0 | 874 | |
michael@0 | 875 | BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs); |
michael@0 | 876 | BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs); |
michael@0 | 877 | BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs); |
michael@0 | 878 | BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs); |
michael@0 | 879 | BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs); |
michael@0 | 880 | BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs); |
michael@0 | 881 | BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs); |
michael@0 | 882 | BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs); |
michael@0 | 883 | BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs); |
michael@0 | 884 | BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs); |
michael@0 | 885 | |
michael@0 | 886 | // FP arithmetic instructions |
michael@0 | 887 | BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 888 | BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 889 | BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 890 | BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 891 | |
michael@0 | 892 | BufferOffset as_abss(FloatRegister fd, FloatRegister fs); |
michael@0 | 893 | BufferOffset as_absd(FloatRegister fd, FloatRegister fs); |
michael@0 | 894 | BufferOffset as_negd(FloatRegister fd, FloatRegister fs); |
michael@0 | 895 | |
michael@0 | 896 | BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 897 | BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 898 | BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 899 | BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft); |
michael@0 | 900 | BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs); |
michael@0 | 901 | BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs); |
michael@0 | 902 | |
michael@0 | 903 | // FP compare instructions |
michael@0 | 904 | BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 905 | FPConditionBit fcc = FCC0); |
michael@0 | 906 | BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 907 | FPConditionBit fcc = FCC0); |
michael@0 | 908 | BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 909 | FPConditionBit fcc = FCC0); |
michael@0 | 910 | BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 911 | FPConditionBit fcc = FCC0); |
michael@0 | 912 | BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 913 | FPConditionBit fcc = FCC0); |
michael@0 | 914 | BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 915 | FPConditionBit fcc = FCC0); |
michael@0 | 916 | BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 917 | FPConditionBit fcc = FCC0); |
michael@0 | 918 | BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft, |
michael@0 | 919 | FPConditionBit fcc = FCC0); |
michael@0 | 920 | |
michael@0 | 921 | // label operations |
michael@0 | 922 | void bind(Label *label, BufferOffset boff = BufferOffset()); |
michael@0 | 923 | void bind(RepatchLabel *label); |
michael@0 | 924 | uint32_t currentOffset() { |
michael@0 | 925 | return nextOffset().getOffset(); |
michael@0 | 926 | } |
michael@0 | 927 | void retarget(Label *label, Label *target); |
michael@0 | 928 | void Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address); |
michael@0 | 929 | |
michael@0 | 930 | // See Bind |
michael@0 | 931 | size_t labelOffsetToPatchOffset(size_t offset) { |
michael@0 | 932 | return actualOffset(offset); |
michael@0 | 933 | } |
michael@0 | 934 | |
michael@0 | 935 | void call(Label *label); |
michael@0 | 936 | void call(void *target); |
michael@0 | 937 | |
michael@0 | 938 | void as_break(uint32_t code); |
michael@0 | 939 | |
michael@0 | 940 | public: |
michael@0 | 941 | static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); |
michael@0 | 942 | static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); |
michael@0 | 943 | |
michael@0 | 944 | protected: |
michael@0 | 945 | InstImm invertBranch(InstImm branch, BOffImm16 skipOffset); |
michael@0 | 946 | void bind(InstImm *inst, uint32_t branch, uint32_t target); |
michael@0 | 947 | void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) { |
michael@0 | 948 | enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind)); |
michael@0 | 949 | if (kind == Relocation::JITCODE) |
michael@0 | 950 | writeRelocation(src); |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | void addLongJump(BufferOffset src) { |
michael@0 | 954 | enoughMemory_ &= longJumps_.append(src.getOffset()); |
michael@0 | 955 | } |
michael@0 | 956 | |
michael@0 | 957 | public: |
michael@0 | 958 | size_t numLongJumps() const { |
michael@0 | 959 | return longJumps_.length(); |
michael@0 | 960 | } |
michael@0 | 961 | uint32_t longJump(size_t i) { |
michael@0 | 962 | return longJumps_[i]; |
michael@0 | 963 | } |
michael@0 | 964 | |
michael@0 | 965 | // Copy the assembly code to the given buffer, and perform any pending |
michael@0 | 966 | // relocations relying on the target address. |
michael@0 | 967 | void executableCopy(uint8_t *buffer); |
michael@0 | 968 | |
michael@0 | 969 | void flushBuffer() { |
michael@0 | 970 | } |
michael@0 | 971 | |
michael@0 | 972 | static uint32_t patchWrite_NearCallSize(); |
michael@0 | 973 | static uint32_t nopSize() { return 4; } |
michael@0 | 974 | |
michael@0 | 975 | static uint32_t extractLuiOriValue(Instruction *inst0, Instruction *inst1); |
michael@0 | 976 | static void updateLuiOriValue(Instruction *inst0, Instruction *inst1, uint32_t value); |
michael@0 | 977 | static void writeLuiOriInstructions(Instruction *inst, Instruction *inst1, |
michael@0 | 978 | Register reg, uint32_t value); |
michael@0 | 979 | |
michael@0 | 980 | static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall); |
michael@0 | 981 | static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue, |
michael@0 | 982 | PatchedImmPtr expectedValue); |
michael@0 | 983 | static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, |
michael@0 | 984 | ImmPtr expectedValue); |
michael@0 | 985 | static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm); |
michael@0 | 986 | static uint32_t alignDoubleArg(uint32_t offset) { |
michael@0 | 987 | return (offset + 1U) &~ 1U; |
michael@0 | 988 | } |
michael@0 | 989 | |
michael@0 | 990 | static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr); |
michael@0 | 991 | |
michael@0 | 992 | static void ToggleToJmp(CodeLocationLabel inst_); |
michael@0 | 993 | static void ToggleToCmp(CodeLocationLabel inst_); |
michael@0 | 994 | |
michael@0 | 995 | static void ToggleCall(CodeLocationLabel inst_, bool enabled); |
michael@0 | 996 | |
michael@0 | 997 | static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst); |
michael@0 | 998 | void processCodeLabels(uint8_t *rawCode); |
michael@0 | 999 | |
michael@0 | 1000 | bool bailed() { |
michael@0 | 1001 | return m_buffer.bail(); |
michael@0 | 1002 | } |
michael@0 | 1003 | }; // Assembler |
michael@0 | 1004 | |
michael@0 | 1005 | // An Instruction is a structure for both encoding and decoding any and all |
michael@0 | 1006 | // MIPS instructions. |
michael@0 | 1007 | class Instruction |
michael@0 | 1008 | { |
michael@0 | 1009 | protected: |
michael@0 | 1010 | // sll zero, zero, 0 |
michael@0 | 1011 | static const uint32_t NopInst = 0x00000000; |
michael@0 | 1012 | |
michael@0 | 1013 | uint32_t data; |
michael@0 | 1014 | |
michael@0 | 1015 | // Standard constructor |
michael@0 | 1016 | Instruction (uint32_t data_) : data(data_) { } |
michael@0 | 1017 | |
michael@0 | 1018 | // You should never create an instruction directly. You should create a |
michael@0 | 1019 | // more specific instruction which will eventually call one of these |
michael@0 | 1020 | // constructors for you. |
michael@0 | 1021 | public: |
michael@0 | 1022 | uint32_t encode() const { |
michael@0 | 1023 | return data; |
michael@0 | 1024 | } |
michael@0 | 1025 | |
michael@0 | 1026 | void makeNop() { |
michael@0 | 1027 | data = NopInst; |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | void setData(uint32_t data) { |
michael@0 | 1031 | this->data = data; |
michael@0 | 1032 | } |
michael@0 | 1033 | |
michael@0 | 1034 | const Instruction & operator=(const Instruction &src) { |
michael@0 | 1035 | data = src.data; |
michael@0 | 1036 | return *this; |
michael@0 | 1037 | } |
michael@0 | 1038 | |
michael@0 | 1039 | // Extract the one particular bit. |
michael@0 | 1040 | uint32_t extractBit(uint32_t bit) { |
michael@0 | 1041 | return (encode() >> bit) & 1; |
michael@0 | 1042 | } |
michael@0 | 1043 | // Extract a bit field out of the instruction |
michael@0 | 1044 | uint32_t extractBitField(uint32_t hi, uint32_t lo) { |
michael@0 | 1045 | return (encode() >> lo) & ((2 << (hi - lo)) - 1); |
michael@0 | 1046 | } |
michael@0 | 1047 | // Since all MIPS instructions have opcode, the opcode |
michael@0 | 1048 | // extractor resides in the base class. |
michael@0 | 1049 | uint32_t extractOpcode() { |
michael@0 | 1050 | return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); |
michael@0 | 1051 | } |
michael@0 | 1052 | // Return the fields at their original place in the instruction encoding. |
michael@0 | 1053 | Opcode OpcodeFieldRaw() const { |
michael@0 | 1054 | return static_cast<Opcode>(encode() & OpcodeMask); |
michael@0 | 1055 | } |
michael@0 | 1056 | |
michael@0 | 1057 | // Get the next instruction in the instruction stream. |
michael@0 | 1058 | // This does neat things like ignoreconstant pools and their guards. |
michael@0 | 1059 | Instruction *next(); |
michael@0 | 1060 | |
michael@0 | 1061 | // Sometimes, an api wants a uint32_t (or a pointer to it) rather than |
michael@0 | 1062 | // an instruction. raw() just coerces this into a pointer to a uint32_t |
michael@0 | 1063 | const uint32_t *raw() const { return &data; } |
michael@0 | 1064 | uint32_t size() const { return 4; } |
michael@0 | 1065 | }; // Instruction |
michael@0 | 1066 | |
michael@0 | 1067 | // make sure that it is the right size |
michael@0 | 1068 | static_assert(sizeof(Instruction) == 4, "Size of Instruction class has to be 4 bytes."); |
michael@0 | 1069 | |
michael@0 | 1070 | class InstNOP : public Instruction |
michael@0 | 1071 | { |
michael@0 | 1072 | public: |
michael@0 | 1073 | InstNOP() |
michael@0 | 1074 | : Instruction(NopInst) |
michael@0 | 1075 | { } |
michael@0 | 1076 | |
michael@0 | 1077 | }; |
michael@0 | 1078 | |
michael@0 | 1079 | // Class for register type instructions. |
michael@0 | 1080 | class InstReg : public Instruction |
michael@0 | 1081 | { |
michael@0 | 1082 | public: |
michael@0 | 1083 | InstReg(Opcode op, Register rd, FunctionField ff) |
michael@0 | 1084 | : Instruction(op | RD(rd) | ff) |
michael@0 | 1085 | { } |
michael@0 | 1086 | InstReg(Opcode op, Register rs, Register rt, FunctionField ff) |
michael@0 | 1087 | : Instruction(op | RS(rs) | RT(rt) | ff) |
michael@0 | 1088 | { } |
michael@0 | 1089 | InstReg(Opcode op, Register rs, Register rt, Register rd, FunctionField ff) |
michael@0 | 1090 | : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff) |
michael@0 | 1091 | { } |
michael@0 | 1092 | InstReg(Opcode op, Register rs, Register rt, Register rd, uint32_t sa, FunctionField ff) |
michael@0 | 1093 | : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff) |
michael@0 | 1094 | { } |
michael@0 | 1095 | InstReg(Opcode op, RSField rs, Register rt, Register rd, uint32_t sa, FunctionField ff) |
michael@0 | 1096 | : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) |
michael@0 | 1097 | { } |
michael@0 | 1098 | InstReg(Opcode op, Register rs, RTField rt, Register rd, uint32_t sa, FunctionField ff) |
michael@0 | 1099 | : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff) |
michael@0 | 1100 | { } |
michael@0 | 1101 | InstReg(Opcode op, Register rs, uint32_t cc, Register rd, uint32_t sa, FunctionField ff) |
michael@0 | 1102 | : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff) |
michael@0 | 1103 | { } |
michael@0 | 1104 | InstReg(Opcode op, uint32_t code, FunctionField ff) |
michael@0 | 1105 | : Instruction(op | code | ff) |
michael@0 | 1106 | { } |
michael@0 | 1107 | // for float point |
michael@0 | 1108 | InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd) |
michael@0 | 1109 | : Instruction(op | rs | RT(rt) | RD(rd)) |
michael@0 | 1110 | { } |
michael@0 | 1111 | InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd, uint32_t sa, FunctionField ff) |
michael@0 | 1112 | : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) |
michael@0 | 1113 | { } |
michael@0 | 1114 | InstReg(Opcode op, RSField rs, Register rt, FloatRegister fs, FloatRegister fd, FunctionField ff) |
michael@0 | 1115 | : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff) |
michael@0 | 1116 | { } |
michael@0 | 1117 | InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fs, FloatRegister fd, FunctionField ff) |
michael@0 | 1118 | : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff) |
michael@0 | 1119 | { } |
michael@0 | 1120 | InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fd, uint32_t sa, FunctionField ff) |
michael@0 | 1121 | : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff) |
michael@0 | 1122 | { } |
michael@0 | 1123 | |
michael@0 | 1124 | uint32_t extractRS () { |
michael@0 | 1125 | return extractBitField(RSShift + RSBits - 1, RSShift); |
michael@0 | 1126 | } |
michael@0 | 1127 | uint32_t extractRT () { |
michael@0 | 1128 | return extractBitField(RTShift + RTBits - 1, RTShift); |
michael@0 | 1129 | } |
michael@0 | 1130 | uint32_t extractRD () { |
michael@0 | 1131 | return extractBitField(RDShift + RDBits - 1, RDShift); |
michael@0 | 1132 | } |
michael@0 | 1133 | uint32_t extractSA () { |
michael@0 | 1134 | return extractBitField(SAShift + SABits - 1, SAShift); |
michael@0 | 1135 | } |
michael@0 | 1136 | uint32_t extractFunctionField () { |
michael@0 | 1137 | return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift); |
michael@0 | 1138 | } |
michael@0 | 1139 | }; |
michael@0 | 1140 | |
michael@0 | 1141 | // Class for branch, load and store instructions with immediate offset. |
michael@0 | 1142 | class InstImm : public Instruction |
michael@0 | 1143 | { |
michael@0 | 1144 | public: |
michael@0 | 1145 | void extractImm16(BOffImm16 *dest); |
michael@0 | 1146 | |
michael@0 | 1147 | InstImm(Opcode op, Register rs, Register rt, BOffImm16 off) |
michael@0 | 1148 | : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
michael@0 | 1149 | { } |
michael@0 | 1150 | InstImm(Opcode op, Register rs, RTField rt, BOffImm16 off) |
michael@0 | 1151 | : Instruction(op | RS(rs) | rt | off.encode()) |
michael@0 | 1152 | { } |
michael@0 | 1153 | InstImm(Opcode op, RSField rs, uint32_t cc, BOffImm16 off) |
michael@0 | 1154 | : Instruction(op | rs | cc | off.encode()) |
michael@0 | 1155 | { } |
michael@0 | 1156 | InstImm(Opcode op, Register rs, Register rt, Imm16 off) |
michael@0 | 1157 | : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
michael@0 | 1158 | { } |
michael@0 | 1159 | InstImm(uint32_t raw) |
michael@0 | 1160 | : Instruction(raw) |
michael@0 | 1161 | { } |
michael@0 | 1162 | // For floating-point loads and stores. |
michael@0 | 1163 | InstImm(Opcode op, Register rs, FloatRegister rt, Imm16 off) |
michael@0 | 1164 | : Instruction(op | RS(rs) | RT(rt) | off.encode()) |
michael@0 | 1165 | { } |
michael@0 | 1166 | |
michael@0 | 1167 | uint32_t extractOpcode() { |
michael@0 | 1168 | return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift); |
michael@0 | 1169 | } |
michael@0 | 1170 | void setOpcode(Opcode op) { |
michael@0 | 1171 | data = (data & ~OpcodeMask) | op; |
michael@0 | 1172 | } |
michael@0 | 1173 | uint32_t extractRS() { |
michael@0 | 1174 | return extractBitField(RSShift + RSBits - 1, RSShift); |
michael@0 | 1175 | } |
michael@0 | 1176 | uint32_t extractRT() { |
michael@0 | 1177 | return extractBitField(RTShift + RTBits - 1, RTShift); |
michael@0 | 1178 | } |
michael@0 | 1179 | void setRT(RTField rt) { |
michael@0 | 1180 | data = (data & ~RTMask) | rt; |
michael@0 | 1181 | } |
michael@0 | 1182 | uint32_t extractImm16Value() { |
michael@0 | 1183 | return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift); |
michael@0 | 1184 | } |
michael@0 | 1185 | void setBOffImm16(BOffImm16 off) { |
michael@0 | 1186 | // Reset immediate field and replace it |
michael@0 | 1187 | data = (data & ~Imm16Mask) | off.encode(); |
michael@0 | 1188 | } |
michael@0 | 1189 | void setImm16(Imm16 off) { |
michael@0 | 1190 | // Reset immediate field and replace it |
michael@0 | 1191 | data = (data & ~Imm16Mask) | off.encode(); |
michael@0 | 1192 | } |
michael@0 | 1193 | }; |
michael@0 | 1194 | |
michael@0 | 1195 | // Class for Jump type instructions. |
michael@0 | 1196 | class InstJump : public Instruction |
michael@0 | 1197 | { |
michael@0 | 1198 | public: |
michael@0 | 1199 | InstJump(Opcode op, JOffImm26 off) |
michael@0 | 1200 | : Instruction(op | off.encode()) |
michael@0 | 1201 | { } |
michael@0 | 1202 | |
michael@0 | 1203 | uint32_t extractImm26Value() { |
michael@0 | 1204 | return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift); |
michael@0 | 1205 | } |
michael@0 | 1206 | }; |
michael@0 | 1207 | |
michael@0 | 1208 | static const uint32_t NumIntArgRegs = 4; |
michael@0 | 1209 | |
michael@0 | 1210 | static inline bool |
michael@0 | 1211 | GetIntArgReg(uint32_t usedArgSlots, Register *out) |
michael@0 | 1212 | { |
michael@0 | 1213 | if (usedArgSlots < NumIntArgRegs) { |
michael@0 | 1214 | *out = Register::FromCode(a0.code() + usedArgSlots); |
michael@0 | 1215 | return true; |
michael@0 | 1216 | } |
michael@0 | 1217 | return false; |
michael@0 | 1218 | } |
michael@0 | 1219 | |
michael@0 | 1220 | // Get a register in which we plan to put a quantity that will be used as an |
michael@0 | 1221 | // integer argument. This differs from GetIntArgReg in that if we have no more |
michael@0 | 1222 | // actual argument registers to use we will fall back on using whatever |
michael@0 | 1223 | // CallTempReg* don't overlap the argument registers, and only fail once those |
michael@0 | 1224 | // run out too. |
michael@0 | 1225 | static inline bool |
michael@0 | 1226 | GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out) |
michael@0 | 1227 | { |
michael@0 | 1228 | // NOTE: We can't properly determine which regs are used if there are |
michael@0 | 1229 | // float arguments. If this is needed, we will have to guess. |
michael@0 | 1230 | JS_ASSERT(usedFloatArgs == 0); |
michael@0 | 1231 | |
michael@0 | 1232 | if (GetIntArgReg(usedIntArgs, out)) |
michael@0 | 1233 | return true; |
michael@0 | 1234 | // Unfortunately, we have to assume things about the point at which |
michael@0 | 1235 | // GetIntArgReg returns false, because we need to know how many registers it |
michael@0 | 1236 | // can allocate. |
michael@0 | 1237 | usedIntArgs -= NumIntArgRegs; |
michael@0 | 1238 | if (usedIntArgs >= NumCallTempNonArgRegs) |
michael@0 | 1239 | return false; |
michael@0 | 1240 | *out = CallTempNonArgRegs[usedIntArgs]; |
michael@0 | 1241 | return true; |
michael@0 | 1242 | } |
michael@0 | 1243 | |
michael@0 | 1244 | static inline uint32_t |
michael@0 | 1245 | GetArgStackDisp(uint32_t usedArgSlots) |
michael@0 | 1246 | { |
michael@0 | 1247 | JS_ASSERT(usedArgSlots >= NumIntArgRegs); |
michael@0 | 1248 | // Even register arguments have place reserved on stack. |
michael@0 | 1249 | return usedArgSlots * sizeof(intptr_t); |
michael@0 | 1250 | } |
michael@0 | 1251 | |
michael@0 | 1252 | } // namespace jit |
michael@0 | 1253 | } // namespace js |
michael@0 | 1254 | |
michael@0 | 1255 | #endif /* jit_mips_Assembler_mips_h */ |