public/jit/x86/assembler-x86.h
author David Anderson <danderson@mozilla.com>
Thu Aug 08 09:41:24 2013 -0700 (2013-08-08)
changeset 3977 fca2b54741ca
child 3979 bdad6d9c8351
permissions -rw-r--r--
Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann)
danderson@3977
     1
/**
danderson@3977
     2
 * vim: set ts=8 sts=2 sw=2 tw=99 et:
danderson@3977
     3
 * =============================================================================
danderson@3977
     4
 * SourcePawn JIT SDK
danderson@3977
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
danderson@3977
     6
 * =============================================================================
danderson@3977
     7
 *
danderson@3977
     8
 * This program is free software; you can redistribute it and/or modify it under
danderson@3977
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
danderson@3977
    10
 * Free Software Foundation.
danderson@3977
    11
 * 
danderson@3977
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
danderson@3977
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
danderson@3977
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
danderson@3977
    15
 * details.
danderson@3977
    16
 *
danderson@3977
    17
 * You should have received a copy of the GNU General Public License along with
danderson@3977
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
danderson@3977
    19
 *
danderson@3977
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
danderson@3977
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
danderson@3977
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
danderson@3977
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
danderson@3977
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
danderson@3977
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
danderson@3977
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
danderson@3977
    27
 * or <http://www.sourcemod.net/license.php>.
danderson@3977
    28
 *
danderson@3977
    29
 * Version: $Id$
danderson@3977
    30
 */
danderson@3977
    31
#ifndef _include_sourcepawn_assembler_x86_h__
danderson@3977
    32
#define _include_sourcepawn_assembler_x86_h__
danderson@3977
    33
danderson@3977
    34
#include <assembler.h>
danderson@3977
    35
#include <ke_vector.h>
danderson@3977
    36
#include <string.h>
danderson@3977
    37
danderson@3977
    38
struct Register
danderson@3977
    39
{
danderson@3977
    40
  const char *name() const {
danderson@3977
    41
    static const char *names[] = {
danderson@3977
    42
      "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
danderson@3977
    43
    };
danderson@3977
    44
    return names[code];
danderson@3977
    45
  }
danderson@3977
    46
danderson@3977
    47
  int code;
danderson@3977
    48
danderson@3977
    49
  bool operator == (const Register &other) const {
danderson@3977
    50
    return code == other.code;
danderson@3977
    51
  }
danderson@3977
    52
  bool operator != (const Register &other) const {
danderson@3977
    53
    return code != other.code;
danderson@3977
    54
  }
danderson@3977
    55
};
danderson@3977
    56
danderson@3977
    57
// X86 has an ancient FPU (called x87) which has a stack of registers
danderson@3977
    58
// numbered st0 through st7.
danderson@3977
    59
struct FpuRegister
danderson@3977
    60
{
danderson@3977
    61
  const char *name() const {
danderson@3977
    62
    static const char *names[] = {
danderson@3977
    63
      "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
danderson@3977
    64
    };
danderson@3977
    65
    return names[code];
danderson@3977
    66
  }
danderson@3977
    67
danderson@3977
    68
  int code;
danderson@3977
    69
danderson@3977
    70
  bool operator == (const FpuRegister &other) const {
danderson@3977
    71
    return code == other.code;
danderson@3977
    72
  }
danderson@3977
    73
  bool operator != (const FpuRegister &other) const {
danderson@3977
    74
    return code != other.code;
danderson@3977
    75
  }
danderson@3977
    76
};
danderson@3977
    77
danderson@3977
    78
struct FloatRegister
danderson@3977
    79
{
danderson@3977
    80
  const char *name() const {
danderson@3977
    81
    static const char *names[] = {
danderson@3977
    82
      "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
danderson@3977
    83
    };
danderson@3977
    84
    return names[code];
danderson@3977
    85
  }
danderson@3977
    86
danderson@3977
    87
  int code;
danderson@3977
    88
danderson@3977
    89
  bool operator == (const FloatRegister &other) const {
danderson@3977
    90
    return code == other.code;
danderson@3977
    91
  }
danderson@3977
    92
  bool operator != (const FloatRegister &other) const {
danderson@3977
    93
    return code != other.code;
danderson@3977
    94
  }
danderson@3977
    95
};
danderson@3977
    96
danderson@3977
    97
const Register eax = { 0 };
danderson@3977
    98
const Register ecx = { 1 };
danderson@3977
    99
const Register edx = { 2 };
danderson@3977
   100
const Register ebx = { 3 };
danderson@3977
   101
const Register esp = { 4 };
danderson@3977
   102
const Register ebp = { 5 };
danderson@3977
   103
const Register esi = { 6 };
danderson@3977
   104
const Register edi = { 7 };
danderson@3977
   105
danderson@3977
   106
const Register r8_al = { 0 };
danderson@3977
   107
const Register r8_cl = { 1 };
danderson@3977
   108
const Register r8_dl = { 2 };
danderson@3977
   109
const Register r8_bl = { 3 };
danderson@3977
   110
const Register r8_ah = { 4 };
danderson@3977
   111
const Register r8_ch = { 5 };
danderson@3977
   112
const Register r8_dh = { 6 };
danderson@3977
   113
const Register r8_bh = { 7 };
danderson@3977
   114
danderson@3977
   115
const FpuRegister st0 = { 0 };
danderson@3977
   116
const FpuRegister st1 = { 1 };
danderson@3977
   117
const FpuRegister st2 = { 2 };
danderson@3977
   118
const FpuRegister st3 = { 3 };
danderson@3977
   119
const FpuRegister st4 = { 4 };
danderson@3977
   120
const FpuRegister st5 = { 5 };
danderson@3977
   121
const FpuRegister st6 = { 6 };
danderson@3977
   122
const FpuRegister st7 = { 7 };
danderson@3977
   123
danderson@3977
   124
const FloatRegister xmm0 = { 0 };
danderson@3977
   125
const FloatRegister xmm1 = { 1 };
danderson@3977
   126
const FloatRegister xmm2 = { 2 };
danderson@3977
   127
const FloatRegister xmm3 = { 3 };
danderson@3977
   128
const FloatRegister xmm4 = { 4 };
danderson@3977
   129
const FloatRegister xmm5 = { 5 };
danderson@3977
   130
const FloatRegister xmm6 = { 6 };
danderson@3977
   131
const FloatRegister xmm7 = { 7 };
danderson@3977
   132
danderson@3977
   133
static const uint8_t kModeDisp0 = 0;
danderson@3977
   134
static const uint8_t kModeDisp8 = 1;
danderson@3977
   135
static const uint8_t kModeDisp32 = 2;
danderson@3977
   136
static const uint8_t kModeReg = 3;
danderson@3977
   137
static const uint8_t kNoIndex = 4;
danderson@3977
   138
static const uint8_t kSIB = 4;
danderson@3977
   139
static const uint8_t kRIP = 5;
danderson@3977
   140
danderson@3977
   141
enum ConditionCode {
danderson@3977
   142
  overflow,
danderson@3977
   143
  no_overflow,
danderson@3977
   144
  below,
danderson@3977
   145
  not_below,
danderson@3977
   146
  equal,
danderson@3977
   147
  not_equal,
danderson@3977
   148
  not_above,
danderson@3977
   149
  above,
danderson@3977
   150
  negative,
danderson@3977
   151
  not_negative,
danderson@3977
   152
  even_parity,
danderson@3977
   153
  odd_parity,
danderson@3977
   154
  less,
danderson@3977
   155
  not_less,
danderson@3977
   156
  not_greater,
danderson@3977
   157
  greater,
danderson@3977
   158
danderson@3977
   159
  zero = equal,
danderson@3977
   160
  not_zero = not_equal,
danderson@3977
   161
  less_equal = not_greater,
danderson@3977
   162
  greater_equal = not_less
danderson@3977
   163
};
danderson@3977
   164
danderson@3977
   165
enum Scale {
danderson@3977
   166
  NoScale,
danderson@3977
   167
  ScaleTwo,
danderson@3977
   168
  ScaleFour,
danderson@3977
   169
  ScaleEight,
danderson@3977
   170
  ScalePointer = ScaleFour
danderson@3977
   171
};
danderson@3977
   172
danderson@3977
   173
struct Operand
danderson@3977
   174
{
danderson@3977
   175
  friend class AssemblerX86;
danderson@3977
   176
danderson@3977
   177
 public:
danderson@3977
   178
  Operand(Register reg, int32_t disp) {
danderson@3977
   179
    if (reg == esp) {
danderson@3977
   180
      // If the reg is esp, we need a SIB encoding.
danderson@3977
   181
      if (disp == 0)
danderson@3977
   182
        sib_disp0(NoScale, kNoIndex, reg.code);
danderson@3977
   183
      else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
danderson@3977
   184
        sib_disp8(NoScale, kNoIndex, reg.code, disp);
danderson@3977
   185
      else
danderson@3977
   186
        sib_disp32(NoScale, kNoIndex, reg.code, disp);
danderson@3977
   187
    } else if (disp == 0 && reg != ebp) {
danderson@3977
   188
      // note, [ebp+0] is disp32/rip
danderson@3977
   189
      modrm_disp0(reg.code);
danderson@3977
   190
    } else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) {
danderson@3977
   191
      modrm_disp8(reg.code, disp);
danderson@3977
   192
    } else {
danderson@3977
   193
      modrm_disp32(reg.code, disp);
danderson@3977
   194
    }
danderson@3977
   195
  }
danderson@3977
   196
danderson@3977
   197
  Operand(Register base, Scale scale, int32_t disp = 0) {
danderson@3977
   198
    if (disp == 0 && base != ebp)
danderson@3977
   199
      sib_disp0(scale, kNoIndex, base.code);
danderson@3977
   200
    else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
danderson@3977
   201
      sib_disp8(scale, kNoIndex, base.code, disp);
danderson@3977
   202
    else
danderson@3977
   203
      sib_disp32(scale, kNoIndex, base.code, disp);
danderson@3977
   204
  }
danderson@3977
   205
danderson@3977
   206
  Operand(Register base, Register index, Scale scale, int32_t disp = 0) {
danderson@3977
   207
    assert(index.code != kNoIndex);
danderson@3977
   208
    if (disp == 0 && base != ebp)
danderson@3977
   209
      sib_disp0(scale, index.code, base.code);
danderson@3977
   210
    else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
danderson@3977
   211
      sib_disp8(scale, index.code, base.code, disp);
danderson@3977
   212
    else
danderson@3977
   213
      sib_disp32(scale, index.code, base.code, disp);
danderson@3977
   214
  }
danderson@3977
   215
danderson@3977
   216
  explicit Operand(ExternalAddress address) {
danderson@3977
   217
    modrm(kModeDisp0, kRIP);
danderson@3977
   218
    *reinterpret_cast<const void **>(bytes_ + 1) = address.address();
danderson@3977
   219
  }
danderson@3977
   220
danderson@3977
   221
  bool isRegister() const {
danderson@3977
   222
    return mode() == kModeReg;
danderson@3977
   223
  }
danderson@3977
   224
  bool isRegister(Register r) const {
danderson@3977
   225
    return mode() == kModeReg && rm() == r.code;
danderson@3977
   226
  }
danderson@3977
   227
  int registerCode() const {
danderson@3977
   228
    return rm();
danderson@3977
   229
  }
danderson@3977
   230
danderson@3977
   231
  uint8_t getByte(size_t index) const {
danderson@3977
   232
    assert(index < length());
danderson@3977
   233
    return bytes_[index];
danderson@3977
   234
  }
danderson@3977
   235
danderson@3977
   236
  size_t length() const {
danderson@3977
   237
    if (mode() == kModeDisp0 && rm() == kRIP)
danderson@3977
   238
      return 5;
danderson@3977
   239
    size_t sib = (mode() != kModeReg && rm() == kSIB);
danderson@3977
   240
    if (mode() == kModeDisp32)
danderson@3977
   241
      return 5 + sib;
danderson@3977
   242
    if (mode() == kModeDisp8)
danderson@3977
   243
      return 2 + sib;
danderson@3977
   244
    return 1 + sib;
danderson@3977
   245
  }
danderson@3977
   246
danderson@3977
   247
 private:
danderson@3977
   248
  explicit Operand(Register reg) {
danderson@3977
   249
    modrm(kModeReg, reg.code);
danderson@3977
   250
  }
danderson@3977
   251
danderson@3977
   252
  void modrm(uint8_t mode, uint8_t rm) {
danderson@3977
   253
    assert(mode <= 3);
danderson@3977
   254
    assert(rm <= 7);
danderson@3977
   255
    bytes_[0] = (mode << 6) | rm;
danderson@3977
   256
  }
danderson@3977
   257
  void modrm_disp0(uint8_t rm) {
danderson@3977
   258
    modrm(kModeDisp0, rm);
danderson@3977
   259
  }
danderson@3977
   260
  void modrm_disp8(uint8_t rm, int8_t disp) {
danderson@3977
   261
    modrm(kModeDisp8, rm);
danderson@3977
   262
    bytes_[1] = disp;
danderson@3977
   263
  }
danderson@3977
   264
  void modrm_disp32(uint8_t rm, int32_t disp) {
danderson@3977
   265
    modrm(kModeDisp32, rm);
danderson@3977
   266
    *reinterpret_cast<int32_t *>(bytes_ + 1) = disp;
danderson@3977
   267
  }
danderson@3977
   268
  void sib(uint8_t mode, Scale scale, uint8_t index, uint8_t base) {
danderson@3977
   269
    modrm(mode, kSIB);
danderson@3977
   270
danderson@3977
   271
    assert(scale <= 3);
danderson@3977
   272
    assert(index <= 7);
danderson@3977
   273
    assert(base <= 7);
danderson@3977
   274
    bytes_[1] = (uint8_t(scale) << 6) | (index << 3) | base;
danderson@3977
   275
  }
danderson@3977
   276
  void sib_disp0(Scale scale, uint8_t index, uint8_t base) {
danderson@3977
   277
    sib(kModeDisp0, scale, index, base);
danderson@3977
   278
  }
danderson@3977
   279
  void sib_disp8(Scale scale, uint8_t index, uint8_t base, int8_t disp) {
danderson@3977
   280
    sib(kModeDisp8, scale, index, base);
danderson@3977
   281
    bytes_[2] = disp;
danderson@3977
   282
  }
danderson@3977
   283
  void sib_disp32(Scale scale, uint8_t index, uint8_t base, int32_t disp) {
danderson@3977
   284
    sib(kModeDisp32, scale, index, base);
danderson@3977
   285
    *reinterpret_cast<int32_t *>(bytes_ + 2) = disp;
danderson@3977
   286
  }
danderson@3977
   287
danderson@3977
   288
 private:
danderson@3977
   289
  uint8_t rm() const {
danderson@3977
   290
    return bytes_[0] & 7;
danderson@3977
   291
  }
danderson@3977
   292
  uint8_t mode() const {
danderson@3977
   293
    return bytes_[0] >> 6;
danderson@3977
   294
  }
danderson@3977
   295
danderson@3977
   296
 private:
danderson@3977
   297
  uint8_t bytes_[6];
danderson@3977
   298
};
danderson@3977
   299
danderson@3977
   300
class AssemblerX86 : public Assembler
danderson@3977
   301
{
danderson@3977
   302
 public:
danderson@3977
   303
  void movl(Register dest, Register src) {
danderson@3977
   304
    emit1(0x89, src.code, dest.code);
danderson@3977
   305
  }
danderson@3977
   306
  void movl(Register dest, const Operand &src) {
danderson@3977
   307
    emit1(0x8b, dest.code, src);
danderson@3977
   308
  }
danderson@3977
   309
  void movl(const Operand &dest, Register src) {
danderson@3977
   310
    emit1(0x89, src.code, dest);
danderson@3977
   311
  }
danderson@3977
   312
  void movl(Register dest, int32_t imm) {
danderson@3977
   313
    emit1(0xb8 + dest.code);
danderson@3977
   314
    writeInt32(imm);
danderson@3977
   315
  }
danderson@3977
   316
  void movl(const Operand &dest, int32_t imm) {
danderson@3977
   317
    if (dest.isRegister())
danderson@3977
   318
      emit1(0xb8 + dest.registerCode());
danderson@3977
   319
    else
danderson@3977
   320
      emit1(0xc7, 0, dest);
danderson@3977
   321
    writeInt32(imm);
danderson@3977
   322
  }
danderson@3977
   323
  void movw(const Operand &dest, Register src) {
danderson@3977
   324
    emit1(0x89, src.code, dest);
danderson@3977
   325
  }
danderson@3977
   326
  void movw(Register dest, const Operand &src) {
danderson@3977
   327
    emit1(0x8b, dest.code, src);
danderson@3977
   328
  }
danderson@3977
   329
  void movb(const Operand &dest, Register src) {
danderson@3977
   330
    emit1(0x88, src.code, dest);
danderson@3977
   331
  }
danderson@3977
   332
  void movb(Register dest, const Operand &src) {
danderson@3977
   333
    emit1(0x8a, dest.code, src);
danderson@3977
   334
  }
danderson@3977
   335
  void movzxb(Register dest, const Operand &src) {
danderson@3977
   336
    emit2(0x0f, 0xb6, dest.code, src);
danderson@3977
   337
  }
danderson@3977
   338
  void movzxb(Register dest, const Register src) {
danderson@3977
   339
    emit2(0x0f, 0xb6, dest.code, src.code);
danderson@3977
   340
  }
danderson@3977
   341
  void movzxw(Register dest, const Operand &src) {
danderson@3977
   342
    emit2(0x0f, 0xb7, dest.code, src);
danderson@3977
   343
  }
danderson@3977
   344
  void movzxw(Register dest, const Register src) {
danderson@3977
   345
    emit2(0x0f, 0xb7, dest.code, src.code);
danderson@3977
   346
  }
danderson@3977
   347
danderson@3977
   348
  void lea(Register dest, const Operand &src) {
danderson@3977
   349
    emit1(0x8d, dest.code, src);
danderson@3977
   350
  }
danderson@3977
   351
danderson@3977
   352
  void xchgl(Register dest, Register src) {
danderson@3977
   353
    if (src == eax)
danderson@3977
   354
      emit1(0x90 + dest.code);
danderson@3977
   355
    else if (dest == eax)
danderson@3977
   356
      emit1(0x90 + src.code);
danderson@3977
   357
    else
danderson@3977
   358
      emit1(0x87, src.code, dest.code);
danderson@3977
   359
  }
danderson@3977
   360
danderson@3977
   361
  void shll_cl(Register dest) {
danderson@3977
   362
    shift_cl(dest.code, 4);
danderson@3977
   363
  }
danderson@3977
   364
  void shll(Register dest, uint8_t imm) {
danderson@3977
   365
    shift_imm(dest.code, 4, imm);
danderson@3977
   366
  }
danderson@3977
   367
  void shll(const Operand &dest, uint8_t imm) {
danderson@3977
   368
    shift_imm(dest, 4, imm);
danderson@3977
   369
  }
danderson@3977
   370
  void shrl_cl(Register dest) {
danderson@3977
   371
    shift_cl(dest.code, 5);
danderson@3977
   372
  }
danderson@3977
   373
  void shrl(Register dest, uint8_t imm) {
danderson@3977
   374
    shift_imm(dest.code, 5, imm);
danderson@3977
   375
  }
danderson@3977
   376
  void shrl(const Operand &dest, uint8_t imm) {
danderson@3977
   377
    shift_imm(dest, 5, imm);
danderson@3977
   378
  }
danderson@3977
   379
  void sarl_cl(Register dest) {
danderson@3977
   380
    shift_cl(dest.code, 7);
danderson@3977
   381
  }
danderson@3977
   382
  void sarl(Register dest, uint8_t imm) {
danderson@3977
   383
    shift_imm(dest.code, 7, imm);
danderson@3977
   384
  }
danderson@3977
   385
  void sarl(const Operand &dest, uint8_t imm) {
danderson@3977
   386
    shift_imm(dest, 7, imm);
danderson@3977
   387
  }
danderson@3977
   388
danderson@3977
   389
  void cmpl(Register left, int32_t imm) {
danderson@3977
   390
    alu_imm(7, imm, Operand(left));
danderson@3977
   391
  }
danderson@3977
   392
  void cmpl(const Operand &left, int32_t imm) {
danderson@3977
   393
    alu_imm(7, imm, left);
danderson@3977
   394
  }
danderson@3977
   395
  void cmpl(Register left, Register right) {
danderson@3977
   396
    emit1(0x39, right.code, left.code);
danderson@3977
   397
  }
danderson@3977
   398
  void cmpl(const Operand &left, Register right) {
danderson@3977
   399
    emit1(0x39, right.code, left);
danderson@3977
   400
  }
danderson@3977
   401
  void cmpl(Register left, const Operand &right) {
danderson@3977
   402
    emit1(0x3b, left.code, right);
danderson@3977
   403
  }
danderson@3977
   404
  void andl(Register dest, int32_t imm) {
danderson@3977
   405
    alu_imm(4, imm, Operand(dest));
danderson@3977
   406
  }
danderson@3977
   407
  void andl(const Operand &dest, int32_t imm) {
danderson@3977
   408
    alu_imm(4, imm, dest);
danderson@3977
   409
  }
danderson@3977
   410
  void andl(Register dest, Register src) {
danderson@3977
   411
    emit1(0x21, src.code, dest.code);
danderson@3977
   412
  }
danderson@3977
   413
  void andl(const Operand &dest, Register src) {
danderson@3977
   414
    emit1(0x21, src.code, dest);
danderson@3977
   415
  }
danderson@3977
   416
  void andl(Register dest, const Operand &src) {
danderson@3977
   417
    emit1(0x23, dest.code, src);
danderson@3977
   418
  }
danderson@3977
   419
  void orl(Register dest, Register src) {
danderson@3977
   420
    emit1(0x09, src.code, dest.code);
danderson@3977
   421
  }
danderson@3977
   422
  void orl(const Operand &dest, Register src) {
danderson@3977
   423
    emit1(0x09, src.code, dest);
danderson@3977
   424
  }
danderson@3977
   425
  void orl(Register dest, const Operand &src) {
danderson@3977
   426
    emit1(0x0b, dest.code, src);
danderson@3977
   427
  }
danderson@3977
   428
  void xorl(Register dest, Register src) {
danderson@3977
   429
    emit1(0x31, src.code, dest.code);
danderson@3977
   430
  }
danderson@3977
   431
  void xorl(const Operand &dest, Register src) {
danderson@3977
   432
    emit1(0x31, src.code, dest);
danderson@3977
   433
  }
danderson@3977
   434
  void xorl(Register dest, const Operand &src) {
danderson@3977
   435
    emit1(0x33, dest.code, src);
danderson@3977
   436
  }
danderson@3977
   437
danderson@3977
   438
  void subl(Register dest, Register src) {
danderson@3977
   439
    emit1(0x29, src.code, dest.code);
danderson@3977
   440
  }
danderson@3977
   441
  void subl(const Operand &dest, Register src) {
danderson@3977
   442
    emit1(0x29, src.code, dest);
danderson@3977
   443
  }
danderson@3977
   444
  void subl(Register dest, const Operand &src) {
danderson@3977
   445
    emit1(0x2b, dest.code, src);
danderson@3977
   446
  }
danderson@3977
   447
  void subl(Register dest, int32_t imm) {
danderson@3977
   448
    alu_imm(5, imm, Operand(dest));
danderson@3977
   449
  }
danderson@3977
   450
  void subl(const Operand &dest, int32_t imm) {
danderson@3977
   451
    alu_imm(5, imm, dest);
danderson@3977
   452
  }
danderson@3977
   453
  void addl(Register dest, Register src) {
danderson@3977
   454
    emit1(0x01, src.code, dest.code);
danderson@3977
   455
  }
danderson@3977
   456
  void addl(const Operand &dest, Register src) {
danderson@3977
   457
    emit1(0x01, src.code, dest);
danderson@3977
   458
  }
danderson@3977
   459
  void addl(Register dest, const Operand &src) {
danderson@3977
   460
    emit1(0x03, dest.code, src);
danderson@3977
   461
  }
danderson@3977
   462
  void addl(Register dest, int32_t imm) {
danderson@3977
   463
    alu_imm(0, imm, Operand(dest));
danderson@3977
   464
  }
danderson@3977
   465
  void addl(const Operand &dest, int32_t imm) {
danderson@3977
   466
    alu_imm(0, imm, dest);
danderson@3977
   467
  }
danderson@3977
   468
danderson@3977
   469
  void imull(Register dest, const Operand &src) {
danderson@3977
   470
    emit2(0x0f, 0xaf, dest.code, src);
danderson@3977
   471
  }
danderson@3977
   472
  void imull(Register dest, Register src) {
danderson@3977
   473
    emit2(0x0f, 0xaf, dest.code, src.code);
danderson@3977
   474
  }
danderson@3977
   475
  void imull(Register dest, const Operand &src, int32_t imm) {
danderson@3977
   476
    if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) {
danderson@3977
   477
      emit1(0x6b, dest.code, src);
danderson@3977
   478
      *pos_++ = imm;
danderson@3977
   479
    } else {
danderson@3977
   480
      emit1(0x69, dest.code, src);
danderson@3977
   481
      writeInt32(imm);
danderson@3977
   482
    }
danderson@3977
   483
  }
danderson@3977
   484
  void imull(Register dest, Register src, int32_t imm) {
danderson@3977
   485
    imull(dest, Operand(src), imm);
danderson@3977
   486
  }
danderson@3977
   487
danderson@3977
   488
  void testl(const Operand &op1, Register op2) {
danderson@3977
   489
    emit1(0x85, op2.code, op1);
danderson@3977
   490
  }
danderson@3977
   491
  void testl(Register op1, Register op2) {
danderson@3977
   492
    emit1(0x85, op2.code, op1.code);
danderson@3977
   493
  }
danderson@3977
   494
  void set(ConditionCode cc, const Operand &dest) {
danderson@3977
   495
    emit2(0x0f, 0x90 + uint8_t(cc), 0, dest);
danderson@3977
   496
  }
danderson@3977
   497
  void set(ConditionCode cc, Register dest) {
danderson@3977
   498
    emit2(0x0f, 0x90 + uint8_t(cc), 0, dest.code);
danderson@3977
   499
  }
danderson@3977
   500
  void negl(Register srcdest) {
danderson@3977
   501
    emit1(0xf7, 3, srcdest.code);
danderson@3977
   502
  }
danderson@3977
   503
  void negl(const Operand &srcdest) {
danderson@3977
   504
    emit1(0xf7, 3, srcdest);
danderson@3977
   505
  }
danderson@3977
   506
  void notl(Register srcdest) {
danderson@3977
   507
    emit1(0xf7, 2, srcdest.code);
danderson@3977
   508
  }
danderson@3977
   509
  void notl(const Operand &srcdest) {
danderson@3977
   510
    emit1(0xf7, 2, srcdest);
danderson@3977
   511
  }
danderson@3977
   512
  void idivl(Register dividend) {
danderson@3977
   513
    emit1(0xf7, 7, dividend.code);
danderson@3977
   514
  }
danderson@3977
   515
  void idivl(const Operand &dividend) {
danderson@3977
   516
    emit1(0xf7, 7, dividend);
danderson@3977
   517
  }
danderson@3977
   518
danderson@3977
   519
  void ret() {
danderson@3977
   520
    emit1(0xc3);
danderson@3977
   521
  }
danderson@3977
   522
  void cld() {
danderson@3977
   523
    emit1(0xfc);
danderson@3977
   524
  }
danderson@3977
   525
  void push(Register reg) {
danderson@3977
   526
    emit1(0x50 + reg.code);
danderson@3977
   527
  }
danderson@3977
   528
  void push(const Operand &src) {
danderson@3977
   529
    if (src.isRegister())
danderson@3977
   530
      emit1(0x50 + src.registerCode());
danderson@3977
   531
    else
danderson@3977
   532
      emit1(0xff, 6, src);
danderson@3977
   533
  }
danderson@3977
   534
  void push(int32_t imm) {
danderson@3977
   535
    emit1(0x68);
danderson@3977
   536
    writeInt32(imm);
danderson@3977
   537
  }
danderson@3977
   538
  void pop(Register reg) {
danderson@3977
   539
    emit1(0x58 + reg.code);
danderson@3977
   540
  }
danderson@3977
   541
  void pop(const Operand &src) {
danderson@3977
   542
    if (src.isRegister())
danderson@3977
   543
      emit1(0x58 + src.registerCode());
danderson@3977
   544
    else
danderson@3977
   545
      emit1(0x8f, 0, src);
danderson@3977
   546
  }
danderson@3977
   547
danderson@3977
   548
  void rep_movsb() {
danderson@3977
   549
    emit2(0xf3, 0xa4);
danderson@3977
   550
  }
danderson@3977
   551
  void rep_movsd() {
danderson@3977
   552
    emit2(0xf3, 0xa5);
danderson@3977
   553
  }
danderson@3977
   554
  void rep_stosd() {
danderson@3977
   555
    emit2(0xf3, 0xab);
danderson@3977
   556
  }
danderson@3977
   557
  void breakpoint() {
danderson@3977
   558
    emit1(0xcc);
danderson@3977
   559
  }
danderson@3977
   560
danderson@3977
   561
  void fld32(const Operand &src) {
danderson@3977
   562
    emit1(0xd9, 0, src);
danderson@3977
   563
  }
danderson@3977
   564
  void fild32(const Operand &src) {
danderson@3977
   565
    emit1(0xdb, 0, src);
danderson@3977
   566
  }
danderson@3977
   567
  void fistp32(const Operand &dest) {
danderson@3977
   568
    emit1(0xdb, 3, dest);
danderson@3977
   569
  }
danderson@3977
   570
  void fadd32(const Operand &src) {
danderson@3977
   571
    emit1(0xd8, 0, src);
danderson@3977
   572
  }
danderson@3977
   573
  void fsub32(const Operand &src) {
danderson@3977
   574
    emit1(0xd8, 4, src);
danderson@3977
   575
  }
danderson@3977
   576
  void fmul32(const Operand &src) {
danderson@3977
   577
    emit1(0xd8, 1, src);
danderson@3977
   578
  }
danderson@3977
   579
  void fdiv32(const Operand &src) {
danderson@3977
   580
    emit1(0xd8, 6, src);
danderson@3977
   581
  }
danderson@3977
   582
  void fstp32(const Operand &dest) {
danderson@3977
   583
    emit1(0xd9, 3, dest);
danderson@3977
   584
  }
danderson@3977
   585
  void fstp(FpuRegister src) {
danderson@3977
   586
    emit2(0xdd, 0xd8 + src.code);
danderson@3977
   587
  }
danderson@3977
   588
  void fldcw(const Operand &src) {
danderson@3977
   589
    emit1(0xd9, 5, src);
danderson@3977
   590
  }
danderson@3977
   591
  void fstcw(const Operand &dest) {
danderson@3977
   592
    emit2(0x9b, 0xd9, 7, dest);
danderson@3977
   593
  }
danderson@3977
   594
  void fsubr32(const Operand &src) {
danderson@3977
   595
    emit1(0xd8, 5, src);
danderson@3977
   596
  }
danderson@3977
   597
danderson@3977
   598
  // Compare st0 with stN.
danderson@3977
   599
  void fucomip(FpuRegister other) {
danderson@3977
   600
    emit2(0xdf, 0xe8 + other.code);
danderson@3977
   601
  }
danderson@3977
   602
danderson@3977
   603
  // At least one argument of these forms must be st0.
danderson@3977
   604
  void fadd32(FpuRegister dest, FpuRegister src) {
danderson@3977
   605
    assert(dest == st0 || src == st0);
danderson@3977
   606
    if (dest == st0)
danderson@3977
   607
      emit2(0xd8, 0xc0 + dest.code);
danderson@3977
   608
    else
danderson@3977
   609
      emit2(0xdc, 0xc0 + src.code);
danderson@3977
   610
  }
danderson@3977
   611
danderson@3977
   612
  void jmp(Label *dest) {
danderson@3977
   613
    int8_t d8;
danderson@3977
   614
    if (canEmitSmallJump(dest, &d8)) {
danderson@3977
   615
      emit2(0xeb, d8);
danderson@3977
   616
    } else {
danderson@3977
   617
      emit1(0xe9);
danderson@3977
   618
      emitJumpTarget(dest);
danderson@3977
   619
    }
danderson@3977
   620
  }
danderson@3977
   621
  void jmp(Register target) {
danderson@3977
   622
    emit1(0xff, 4, target.code);
danderson@3977
   623
  }
danderson@3977
   624
  void jmp(const Operand &target) {
danderson@3977
   625
    emit1(0xff, 4, target);
danderson@3977
   626
  }
danderson@3977
   627
  void j(ConditionCode cc, Label *dest) {
danderson@3977
   628
    int8_t d8;
danderson@3977
   629
    if (canEmitSmallJump(dest, &d8)) {
danderson@3977
   630
      emit2(0x70 + uint8_t(cc), d8);
danderson@3977
   631
    } else {
danderson@3977
   632
      emit2(0x0f, 0x80 + uint8_t(cc));
danderson@3977
   633
      emitJumpTarget(dest);
danderson@3977
   634
    }
danderson@3977
   635
  }
danderson@3977
   636
  void call(Label *dest) {
danderson@3977
   637
    emit1(0xe8);
danderson@3977
   638
    emitJumpTarget(dest);
danderson@3977
   639
  }
danderson@3977
   640
  void bind(Label *target) {
danderson@3977
   641
    if (outOfMemory()) {
danderson@3977
   642
      // If we ran out of memory, the code stream is potentially invalid and
danderson@3977
   643
      // we cannot use the embedded linked list.
danderson@3977
   644
      target->bind(pc());
danderson@3977
   645
      return;
danderson@3977
   646
    }
danderson@3977
   647
danderson@3977
   648
    assert(!target->bound());
danderson@3977
   649
    uint32_t status = target->status();
danderson@3977
   650
    while (Label::More(status)) {
danderson@3977
   651
      // Grab the offset. It should be at least a 1byte op + rel32.
danderson@3977
   652
      uint32_t offset = Label::ToOffset(status);
danderson@3977
   653
      assert(offset >= 5);
danderson@3977
   654
danderson@3977
   655
      // Grab the delta from target to pc.
danderson@3977
   656
      ptrdiff_t delta = pos_ - (buffer() + offset);
danderson@3977
   657
      assert(delta >= INT_MIN && delta <= INT_MAX);
danderson@3977
   658
danderson@3977
   659
      int32_t *p = reinterpret_cast<int32_t *>(buffer() + offset - 4);
danderson@3977
   660
      status = *p;
danderson@3977
   661
      *p = delta;
danderson@3977
   662
    }
danderson@3977
   663
    target->bind(pc());
danderson@3977
   664
  }
danderson@3977
   665
danderson@3977
   666
  void bind(DataLabel *address) {
danderson@3977
   667
    if (outOfMemory())
danderson@3977
   668
      return;
danderson@3977
   669
    if (address->used()) {
danderson@3977
   670
      uint32_t offset = DataLabel::ToOffset(address->status());
danderson@3977
   671
      *reinterpret_cast<int32_t *>(buffer() + offset - 4) = position() - int32_t(offset);
danderson@3977
   672
    }
danderson@3977
   673
    address->bind(pc());
danderson@3977
   674
  }
danderson@3977
   675
  void movl(Register dest, DataLabel *src) {
danderson@3977
   676
    emit1(0xb8 + dest.code);
danderson@3977
   677
    if (src->bound()) {
danderson@3977
   678
      writeInt32(int32_t(src->offset()) - (position() + 4));
danderson@3977
   679
    } else {
danderson@3977
   680
      writeInt32(0xabcdef0);
danderson@3977
   681
      src->use(pc());
danderson@3977
   682
    }
danderson@3977
   683
    if (!local_refs_.append(pc()))
danderson@3977
   684
      outOfMemory_ = true;
danderson@3977
   685
  }
danderson@3977
   686
  void emit_absolute_address(Label *address) {
danderson@3977
   687
    if (address->bound())
danderson@3977
   688
      writeUint32(int32_t(address->offset()) - (position() + 4));
danderson@3977
   689
    else
danderson@3977
   690
      writeUint32(address->addPending(position() + 4));
danderson@3977
   691
    if (!local_refs_.append(pc()))
danderson@3977
   692
      outOfMemory_ = true;
danderson@3977
   693
  }
danderson@3977
   694
danderson@3977
   695
  void call(Register target) {
danderson@3977
   696
    emit1(0xff, 2, target.code);
danderson@3977
   697
  }
danderson@3977
   698
  void call(const Operand &target) {
danderson@3977
   699
    emit1(0xff, 2, target);
danderson@3977
   700
  }
danderson@3977
   701
  void call(ExternalAddress address) {
danderson@3977
   702
    emit1(0xe8);
danderson@3977
   703
    writeInt32(address.value());
danderson@3977
   704
    if (!external_refs_.append(pc()))
danderson@3977
   705
      outOfMemory_ = true;
danderson@3977
   706
  }
danderson@3977
   707
  void jmp(ExternalAddress address) {
danderson@3977
   708
    assert(sizeof(address) == sizeof(int32_t));
danderson@3977
   709
    emit1(0xe9);
danderson@3977
   710
    writeInt32(address.value());
danderson@3977
   711
    if (!external_refs_.append(pc()))
danderson@3977
   712
      outOfMemory_ = true;
danderson@3977
   713
  }
danderson@3977
   714
danderson@3977
   715
  static void PatchRel32Absolute(uint8_t *ip, void *ptr) {
danderson@3977
   716
    int32_t delta = uint32_t(ptr) - uint32_t(ip);
danderson@3977
   717
    *reinterpret_cast<int32_t *>(ip - 4) = delta;
danderson@3977
   718
  }
danderson@3977
   719
danderson@3977
   720
  void emitToExecutableMemory(void *code) {
danderson@3977
   721
    assert(!outOfMemory());
danderson@3977
   722
danderson@3977
   723
    // Relocate anything we emitted as rel32 with an external pointer.
danderson@3977
   724
    uint8_t *base = reinterpret_cast<uint8_t *>(code);
danderson@3977
   725
    memcpy(base, buffer(), length());
danderson@3977
   726
    for (size_t i = 0; i < external_refs_.length(); i++) {
danderson@3977
   727
      size_t offset = external_refs_[i];
danderson@3977
   728
      PatchRel32Absolute(base + offset, *reinterpret_cast<void **>(base + offset - 4));
danderson@3977
   729
    }
danderson@3977
   730
danderson@3977
   731
    // Relocate everything we emitted as an abs32 with an internal offset. Note
danderson@3977
   732
    // that in the code stream, we use relative offsets so we can use both Label
danderson@3977
   733
    // and DataLabel.
danderson@3977
   734
    for (size_t i = 0; i < local_refs_.length(); i++) {
danderson@3977
   735
      size_t offset = local_refs_[i];
danderson@3977
   736
      int32_t delta = *reinterpret_cast<int32_t *>(base + offset - 4);
danderson@3977
   737
      *reinterpret_cast<void **>(base + offset - 4) = base + offset + delta;
danderson@3977
   738
    }
danderson@3977
   739
  }
danderson@3977
   740
danderson@3977
   741
  void align(uint32_t bytes) {
danderson@3977
   742
    int32_t delta = (pc() & ~(bytes - 1)) + bytes - pc();
danderson@3977
   743
    for (int32_t i = 0; i < delta; i++)
danderson@3977
   744
      emit1(0xcc);
danderson@3977
   745
  }
danderson@3977
   746
danderson@3977
   747
 private:
danderson@3977
   748
  bool canEmitSmallJump(Label *dest, int8_t *deltap) {
danderson@3977
   749
    if (!dest->bound())
danderson@3977
   750
      return false;
danderson@3977
   751
danderson@3977
   752
    // All small jumps are assumed to be 2 bytes.
danderson@3977
   753
    ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 2);
danderson@3977
   754
    if (delta < SCHAR_MIN || delta > SCHAR_MAX)
danderson@3977
   755
      return false;
danderson@3977
   756
    *deltap = delta;
danderson@3977
   757
    return true;
danderson@3977
   758
  }
danderson@3977
   759
  void emitJumpTarget(Label *dest) {
danderson@3977
   760
    if (dest->bound()) {
danderson@3977
   761
      ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 4);
danderson@3977
   762
      assert(delta >= INT_MIN && delta <= INT_MAX);
danderson@3977
   763
      writeInt32(delta);
danderson@3977
   764
    } else {
danderson@3977
   765
      writeUint32(dest->addPending(position() + 4));
danderson@3977
   766
    }
danderson@3977
   767
  }
danderson@3977
   768
danderson@3977
   769
  void emit(uint8_t reg, const Operand &operand) {
danderson@3977
   770
    *pos_++ = operand.getByte(0) | (reg << 3);
danderson@3977
   771
    size_t length = operand.length();
danderson@3977
   772
    for (size_t i = 1; i < length; i++)
danderson@3977
   773
      *pos_++ = operand.getByte(i);
danderson@3977
   774
  }
danderson@3977
   775
danderson@3977
   776
  void emit1(uint8_t opcode) {
danderson@3977
   777
    ensureSpace();
danderson@3977
   778
    *pos_++ = opcode;
danderson@3977
   779
  }
danderson@3977
   780
  void emit1(uint8_t opcode, uint8_t reg, uint8_t opreg) {
danderson@3977
   781
    ensureSpace();
danderson@3977
   782
    assert(reg <= 7);
danderson@3977
   783
    assert(opreg <= 7);
danderson@3977
   784
    *pos_++ = opcode;
danderson@3977
   785
    *pos_++ = (kModeReg << 6) | (reg << 3) | opreg;
danderson@3977
   786
  }
danderson@3977
   787
  void emit1(uint8_t opcode, uint8_t reg, const Operand &operand) {
danderson@3977
   788
    ensureSpace();
danderson@3977
   789
    assert(reg <= 7);
danderson@3977
   790
    *pos_++ = opcode;
danderson@3977
   791
    emit(reg, operand);
danderson@3977
   792
  }
danderson@3977
   793
danderson@3977
   794
  void emit2(uint8_t prefix, uint8_t opcode) {
danderson@3977
   795
    ensureSpace();
danderson@3977
   796
    *pos_++ = prefix;
danderson@3977
   797
    *pos_++ = opcode;
danderson@3977
   798
  }
danderson@3977
   799
  void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, uint8_t opreg) {
danderson@3977
   800
    emit2(prefix, opcode);
danderson@3977
   801
    assert(reg <= 7);
danderson@3977
   802
    *pos_++ = (kModeReg << 6) | (reg << 3) | opreg;
danderson@3977
   803
  }
danderson@3977
   804
  void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, const Operand &operand) {
danderson@3977
   805
    emit2(prefix, opcode);
danderson@3977
   806
    emit(reg, operand);
danderson@3977
   807
  }
danderson@3977
   808
danderson@3977
   809
  template <typename T>
danderson@3977
   810
  void shift_cl(const T &t, uint8_t r) {
danderson@3977
   811
    emit1(0xd3, r, t);
danderson@3977
   812
  }
danderson@3977
   813
danderson@3977
   814
  template <typename T>
danderson@3977
   815
  void shift_imm(const T &t, uint8_t r, int32_t imm) {
danderson@3977
   816
    if (imm == 1) {
danderson@3977
   817
      emit1(0xd1, r, t);
danderson@3977
   818
    } else {
danderson@3977
   819
      emit1(0xc1, r, t);
danderson@3977
   820
      *pos_++ = imm & 0x1F;
danderson@3977
   821
    }
danderson@3977
   822
  }
danderson@3977
   823
  void alu_imm(uint8_t r, int32_t imm, const Operand &operand) {
danderson@3977
   824
    if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) {
danderson@3977
   825
      emit1(0x83, r, operand);
danderson@3977
   826
      *pos_++ = uint8_t(imm & 0xff);
danderson@3977
   827
    } else if (operand.isRegister(eax)) {
danderson@3977
   828
      emit1(0x05 | (r << 3));
danderson@3977
   829
      writeInt32(imm);
danderson@3977
   830
    } else {
danderson@3977
   831
      emit1(0x81, r, operand);
danderson@3977
   832
      writeInt32(imm);
danderson@3977
   833
    }
danderson@3977
   834
  }
danderson@3977
   835
danderson@3977
   836
 private:
danderson@3977
   837
  ke::Vector<uint32_t> external_refs_;
danderson@3977
   838
  ke::Vector<uint32_t> local_refs_;
danderson@3977
   839
};
danderson@3977
   840
danderson@3977
   841
#endif // _include_sourcepawn_assembler_x86_h__
danderson@3977
   842