js/src/jit/mips/Assembler-mips.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 &current() { 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 */

mercurial