Exemplo n.º 1
0
void reclaimTranslation(TransLoc loc) {
  BlockingLeaseHolder writer(Translator::WriteLease());

  ITRACE(1, "Reclaiming translation M[{}, {}] C[{}, {}] F[{}, {}]\n",
         loc.mainStart(), loc.mainEnd(), loc.coldStart(), loc.coldEnd(),
         loc.frozenStart(), loc.frozenEnd());

  Trace::Indent _i;

  auto& cache = mcg->code();
  cache.blockFor(loc.mainStart()).free(loc.mainStart(), loc.mainSize());
  cache.blockFor(loc.coldStart()).free(loc.coldStart(), loc.coldSize());
  if (loc.coldStart() != loc.frozenStart()) {
    cache.blockFor(loc.frozenStart()).free(loc.frozenStart(), loc.frozenSize());
  }

  for (auto it = s_smashedBranches.begin(); it != s_smashedBranches.end();) {
    auto br = it++;
    if (loc.contains(br->first)) {
      ITRACE(1, "Erasing smashed branch @ {} from SrcRec addr={}\n",
             br->first, (void*)br->second);
      br->second->removeIncomingBranch(br->first);
      s_smashedBranches.erase(br);
    }
  }

  // Erase meta-data about these regions of the TC
  {
    ITRACE(1, "Clearing translation meta-data\n");
    Trace::Indent _i;
    clearTCMaps(loc.mainStart(), loc.mainEnd());
    clearTCMaps(loc.coldCodeStart(), loc.coldEnd());
    clearTCMaps(loc.frozenCodeStart(), loc.frozenEnd());
  }

  if (debug) {
    // Ensure no one calls into the function
    ITRACE(1, "Overwriting function\n");
    auto clearBlock = [] (CodeBlock& cb) {
      X64Assembler a {cb};
      while (cb.available() >= 2) a.ud2();
      if (cb.available() > 0) a.int3();
      always_assert(!cb.available());
    };

    CodeBlock main, cold, frozen;
    main.init(loc.mainStart(), loc.mainSize(), "Dead Main");
    cold.init(loc.coldStart(), loc.coldSize(), "Dead Cold");
    frozen.init(loc.frozenStart(), loc.frozenSize(), "Dead Frozen");

    clearBlock(main);
    clearBlock(cold);
    clearBlock(frozen);
  }
}
Exemplo n.º 2
0
void smashJcc(TCA inst, TCA target, ConditionCode cc) {
  always_assert(is_aligned(inst, Alignment::SmashJcc));

  if (cc == CC_None) {
    X64Assembler::patchJcc(inst, target);
  } else {
    auto& cb = mcg->code().blockFor(inst);
    CodeCursor cursor { cb, inst };
    X64Assembler a { cb };
    a.jcc(cc, target);
  }
}
Exemplo n.º 3
0
void smashJmp(TCA inst, TCA target) {
  always_assert(is_aligned(inst, Alignment::SmashJmp));

  auto& cb = mcg->code().blockFor(inst);
  CodeCursor cursor { cb, inst };
  X64Assembler a { cb };

  if (target > inst && target - inst <= smashableJmpLen()) {
    a.emitNop(target - inst);
  } else {
    a.jmp(target);
  }
}
Exemplo n.º 4
0
StoreImmPatcher::StoreImmPatcher(X64Assembler& as, uint64_t initial,
                                 register_name_t reg,
                                 int32_t offset, register_name_t base) {
  is32 = deltaFits(initial, sz::dword);
  if (is32) {
    as.store_imm64_disp_reg64(initial, offset, base);
  } else {
    as.mov_imm64_reg(initial, reg);
    as.store_reg64_disp_reg64(reg, offset, base);
  }
  m_addr = as.code.frontier - (is32 ? 4 : 8);
  ASSERT((is32 ? (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr) == initial);
}
Exemplo n.º 5
0
StoreImmPatcher::StoreImmPatcher(X64Assembler& as, uint64_t initial,
                                 RegNumber reg,
                                 int32_t offset, RegNumber base) {
  m_is32 = deltaFits(initial, sz::dword);
  if (m_is32) {
    as.store_imm64_disp_reg64(initial, offset, base);
  } else {
    as.mov_imm64_reg(initial, reg);
    as.store_reg64_disp_reg64(reg, offset, base);
  }
  m_addr = as.frontier() - (m_is32 ? 4 : 8);
  assert((m_is32 ?  (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr)
         == initial);
}
Exemplo n.º 6
0
  void operator()() {
    auto codeLock = mcg->lockCode();

    for (auto& e : entries) {
      CodeBlock cb;
      cb.init(e.first, e.second - e.first, "relocated");
      X64Assembler a { cb };
      while (a.canEmit(2)) {
        a.ud2();
      }
      if (a.canEmit(1)) a.int3();
    }
    okToRelocate = true;
  }
Exemplo n.º 7
0
std::pair<TCA,TCA>
emitSmashableJccAndJmp(CodeBlock& cb, TCA target, ConditionCode cc) {
  assertx(cc != CC_None);

  align(cb, Alignment::SmashJccAndJmp, AlignContext::Live);

  X64Assembler a { cb };
  auto const jcc = cb.frontier();
  a.jcc(cc, target);
  auto const jmp = cb.frontier();
  a.jmp(target);

  return std::make_pair(jcc, jmp);
}
Exemplo n.º 8
0
/*
 * Satisfy an alignment constraint. Bridge the gap with int3's.
 */
void moveToAlign(CodeBlock& cb,
                 const size_t align /* =kJmpTargetAlign */) {
  X64Assembler a { cb };
  assertx(folly::isPowTwo(align));
  size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier()));
  if (leftInBlock == align) return;
  if (leftInBlock > 2) {
    a.ud2();
    leftInBlock -= 2;
  }
  if (leftInBlock > 0) {
    a.emitInt3s(leftInBlock);
  }
}
Exemplo n.º 9
0
void smashCall(TCA inst, TCA target) {
  always_assert(is_aligned(inst, Alignment::SmashCall));
  /*
   * TODO(#7889486): We'd like this just to be:
   *
   *    X64Assembler::patchCall(inst, target);
   *
   * but presently this causes asserts to fire in MCGenerator because of a bug
   * with PGO and relocation.
   */
  auto& cb = mcg->code().blockFor(inst);
  CodeCursor cursor { cb, inst };
  X64Assembler a { cb };
  a.call(target);
}
Exemplo n.º 10
0
StoreImmPatcher::StoreImmPatcher(CodeBlock& cb, uint64_t initial,
                                 RegNumber reg,
                                 int32_t offset, RegNumber base) {
  X64Assembler as { cb };
  m_is32 = deltaFits(initial, sz::dword);
  if (m_is32) {
    as.store_imm64_disp_reg64(initial, offset, base);
    m_addr = cb.frontier() - 4;
  } else {
    as.mov_imm64_reg(initial, reg);
    m_addr = cb.frontier() - 8;
    as.store_reg64_disp_reg64(reg, offset, base);
  }
  assert((m_is32 ?  (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr)
         == initial);
}
Exemplo n.º 11
0
  void operator()() {
    LeaseHolder writer(Translator::WriteLease());
    if (!writer) {
      Treadmill::enqueue(std::move(*this));
      return;
    }

    for (auto& e : entries) {
      CodeBlock cb;
      cb.init(e.first, e.second - e.first, "relocated");
      X64Assembler a { cb };
      while (a.canEmit(2)) {
        a.ud2();
      }
      if (a.canEmit(1)) a.int3();
    }
    okToRelocate = true;
  }
Exemplo n.º 12
0
/*
 * Satisfy an alignment constraint. Bridge the gap with int3's.
 */
void moveToAlign(CodeBlock& cb,
                 const size_t align /* =kJmpTargetAlign */) {
  // TODO(2967396) implement properly, move function
  if (arch() == Arch::ARM) return;

  using namespace HPHP::Util;
  X64Assembler a { cb };
  assert(isPowerOfTwo(align));
  size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier()));
  if (leftInBlock == align) return;
  if (leftInBlock > 2) {
    a.ud2();
    leftInBlock -= 2;
  }
  if (leftInBlock > 0) {
    a.emitInt3s(leftInBlock);
  }
}
Exemplo n.º 13
0
/*
 * Satisfy an alignment constraint. Bridge the gap with int3's.
 */
void moveToAlign(CodeBlock& cb,
                 const size_t align /* =kJmpTargetAlign */) {
    switch (arch()) {
    case Arch::X64: {
        X64Assembler a { cb };
        assert(folly::isPowTwo(align));
        size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier()));
        if (leftInBlock == align) return;
        if (leftInBlock > 2) {
            a.ud2();
            leftInBlock -= 2;
        }
        break;
    }
    case Arch::ARM:
        // TODO(2967396) implement properly, move function
        break;
    }
}
Exemplo n.º 14
0
void emitFuncGuard(const Func* func, CodeBlock& cb) {
  using namespace reg;
  X64Assembler a { cb };

  assertx(x64::abi(CodeKind::CrossTrace).gpUnreserved.contains(rax));

  TCA start DEBUG_ONLY = a.frontier();

  auto const funcImm = Immed64(func);

  if (funcImm.fits(sz::dword)) {
    emitSmashableCmpq(a.code(), funcImm.l(), rVmFp,
                      safe_cast<int8_t>(AROFF(m_func)));
  } else {
    // Although func doesn't fit in a signed 32-bit immediate, it may still fit
    // in an unsigned one.  Rather than deal with yet another case (which only
    // happens when we disable jemalloc), just emit a smashable mov followed by
    // a register cmp.
    emitSmashableMovq(a.code(), uint64_t(func), rax);
    a.  cmpq   (rax, rVmFp[AROFF(m_func)]);
  }
  a.    jnz    (mcg->tx().uniqueStubs.funcPrologueRedispatch);

  assertx(funcPrologueToGuard(a.frontier(), func) == start);
  assertx(funcPrologueHasGuard(a.frontier(), func));
}
Exemplo n.º 15
0
void emitFuncGuard(const Func* func, CodeBlock& cb, CGMeta& fixups) {
  using namespace reg;
  X64Assembler a { cb };

  assertx(x64::abi(CodeKind::CrossTrace).gpUnreserved.contains(rax));

  auto const funcImm = Immed64(func);

  if (funcImm.fits(sz::dword)) {
    emitSmashableCmpq(a.code(), fixups, funcImm.l(), rvmfp(),
                      safe_cast<int8_t>(AROFF(m_func)));
  } else {
    // Although func doesn't fit in a signed 32-bit immediate, it may still fit
    // in an unsigned one.  Rather than deal with yet another case (which only
    // happens when we disable jemalloc), just emit a smashable mov followed by
    // a register cmp.
    emitSmashableMovq(a.code(), fixups, uint64_t(func), rax);
    a.  cmpq   (rax, rvmfp()[AROFF(m_func)]);
  }
  a.    jnz    (tc::ustubs().funcPrologueRedispatch);

  DEBUG_ONLY auto guard = funcGuardFromPrologue(a.frontier(), func);
  assertx(funcGuardMatches(guard, func));
}
Exemplo n.º 16
0
void emitFuncGuard(const Func* func, CodeBlock& cb) {
  using namespace reg;
  X64Assembler a { cb };

  assertx(cross_trace_abi.gpUnreserved.contains(rax));

  auto const funcImm = Immed64(func);
  int nbytes, offset;

  if (!funcImm.fits(sz::dword)) {
    nbytes = kFuncGuardSmash;
    offset = kFuncGuardImm;
  } else {
    nbytes = kFuncGuardShortSmash;
    offset = kFuncGuardShortImm;
  }
  mcg->backEnd().prepareForSmash(a.code(), nbytes, offset);

  TCA start DEBUG_ONLY = a.frontier();

  if (!funcImm.fits(sz::dword)) {
    // Although func doesnt fit in a signed 32-bit immediate, it may still fit
    // in an unsigned one.  Rather than deal with yet another case (which only
    // happens when we disable jemalloc), just force it to be an 8-byte
    // immediate, and patch it up afterwards.
    a.  movq   (0xdeadbeeffeedface, rax);

    auto immptr = reinterpret_cast<uintptr_t*>(a.frontier()) - 1;
    assertx(*immptr == 0xdeadbeeffeedface);
    *immptr = uintptr_t(func);

    a.  cmpq   (rax, rVmFp[AROFF(m_func)]);
  } else {
    a.  cmpq   (funcImm.l(), rVmFp[AROFF(m_func)]);
  }
  a.    jnz    (mcg->tx().uniqueStubs.funcPrologueRedispatch);

  assertx(funcPrologueToGuard(a.frontier(), func) == start);
  assertx(funcPrologueHasGuard(a.frontier(), func));
}
Exemplo n.º 17
0
MovImmPatcher::MovImmPatcher(X64Assembler& as, uint64_t initial,
                             register_name_t reg) {
  is32 = deltaFits(initial, sz::dword);
  as.mov_imm64_reg(initial, reg);
  m_addr = as.code.frontier - (is32 ? 4 : 8);
}
Exemplo n.º 18
0
TCA emitCallToExit(CodeBlock& cb) {
  X64Assembler a { cb };

  // Emit a byte of padding. This is a kind of hacky way to avoid
  // hitting an assert in recordGdbStub when we call it with stub - 1
  // as the start address.
  a.emitNop(1);
  auto const start = a.frontier();
  if (RuntimeOption::EvalHHIRGenerateAsserts) {
    Label ok;
    a.emitImmReg(uintptr_t(enterTCExit), reg::rax);
    a.cmpq(reg::rax, *rsp());
    a.je8 (ok);
    a.ud2();
  asm_label(a, ok);
  }

  // Emulate a ret to enterTCExit without actually doing one to avoid
  // unbalancing the return stack buffer. The call from enterTCHelper() that
  // got us into the TC was popped off the RSB by the ret that got us to this
  // stub.
  a.addq(8, rsp());
  if (a.jmpDeltaFits(TCA(enterTCExit))) {
    a.jmp(TCA(enterTCExit));
  } else {
    // can't do a near jmp and a rip-relative load/jmp would require threading
    // through extra state to allocate a literal. use an indirect jump through
    // a register
    a.emitImmReg(uintptr_t(enterTCExit), reg::rax);
    a.jmp(reg::rax);
  }

  // On a backtrace, gdb tries to locate the calling frame at address
  // returnRIP-1. However, for the first VM frame, there is no code at
  // returnRIP-1, since the AR was set up manually. For this frame,
  // record the tracelet address as starting from this callToExit-1,
  // so gdb does not barf.
  return start;
}
Exemplo n.º 19
0
void PhysRegSaverParity::emitPops(X64Assembler& as, RegSet regs) {
  emitPops(Vauto(as.code()).main(), regs);
}
Exemplo n.º 20
0
PhysRegSaverParity::PhysRegSaverParity(int parity, X64Assembler& as,
                                       RegSet regs)
  : PhysRegSaverParity{parity, Vauto(as.code()).main(), regs} {
  m_v = nullptr;
  m_as = &as;
}
Exemplo n.º 21
0
void testEmitMethods() {
  X64Assembler e;
  e.init(10 << 20);

  using namespace HPHP::VM::Transl::reg;

  int n = sizeof(instr_list) / sizeof(instr_list[0]);
  for (int i = 0; i < n; ++i) {

    X64Instr op = instr_list[i];
    printf("%s:\n", instr_names[i]);

    if (supported_AM[i] & MASK_none) {
      printf("  Address mode: none\n");
      e.emit(op);
    }

    if (supported_AM[i] & MASK_R) {
      printf("  Address mode: R\n");
      e.emitR(op, rax);
      e.emitR(op, rsi);
      e.emitR(op, rbp);
      e.emitR(op, rsp);
      e.emitR(op, r8);
      e.emitR(op, r15);
      e.emitR(op, r13);
      e.emitR(op, r12);
    }

    if (supported_AM[i] & MASK_RR) {
      printf("  Address mode: RR\n");
      e.emitRR(op, rsi, rax);
      e.emitRR(op, rax, rdi);
      e.emitRR(op, rsi, rdi);
      e.emitRR(op, rbp, rsp);
      e.emitRR(op, rsp, rbp);
      e.emitRR(op, rsi, r8);
      e.emitRR(op, rax, r15);
      e.emitRR(op, rsi, r15);
      e.emitRR(op, rbp, r12);
      e.emitRR(op, rsp, r13);
      e.emitRR(op, r14, rax);
      e.emitRR(op, r8,  rdi);
      e.emitRR(op, r14, rdi);
      e.emitRR(op, r13, rsp);
      e.emitRR(op, r12, rbp);
      e.emitRR(op, r14, r8);
      e.emitRR(op, r8,  r15);
      e.emitRR(op, r14, r15);
      e.emitRR(op, r13, r12);
      e.emitRR(op, r12, r13);
      e.emitRR(op, rax, rax);
      e.emitRR(op, rax, r8);
      e.emitRR(op, r8, rax);
      e.emitRR(op, r8, r8);
    }

    if (supported_AM[i] & MASK_I) {
      printf("  Address mode: I\n");
      e.emitI(op, -128);
      e.emitI(op, 127);
      e.emitI(op, 0xF1);
      e.emitI(op, 1);
    }

    if (supported_AM[i] & MASK_IR) {
      printf("  Address mode: IR\n");
      e.emitIR(op, rbx, 1);
      e.emitIR(op, rax, -128);
      e.emitIR(op, rsi, -128);
      e.emitIR(op, rbp, 127);
      e.emitIR(op, rsp, 0xF1);
      e.emitIR(op, rsp, 1);
      e.emitIR(op, r11, 1);
      e.emitIR(op, r8, -128);
      e.emitIR(op, r14, -128);
      e.emitIR(op, r13, 127);
      e.emitIR(op, r12, 0xF1);
      e.emitIR(op, r12, 1);
      if (i == 13 /*instr_mov*/) {
        e.emitIR(op, rax, (ssize_t)0x1234123412341234);
        e.emitIR(op, r8, (ssize_t)0x1234123412341234);
      }
    }

    if (supported_AM[i] & MASK_IRR) {
      printf("  Address mode: IRR\n");
      e.emitIRR(op, rsi, rax, -128);
      e.emitIRR(op, rax, rdi, -128);
      e.emitIRR(op, rbp, rsp, 127);
      e.emitIRR(op, rsp, rbp, 0xF1);
      e.emitIRR(op, rsp, rbp, 1);
      e.emitIRR(op, r14, rax, -128);
      e.emitIRR(op, r8, rdi, -128);
      e.emitIRR(op, r13, rsp, 127);
      e.emitIRR(op, r12, rbp, 0xF1);
      e.emitIRR(op, r12, rbp, 1);
      e.emitIRR(op, rsi, r8, -128);
      e.emitIRR(op, rax, r15, -128);
      e.emitIRR(op, rbp, r12, 127);
      e.emitIRR(op, rsp, r13, 0xF1);
      e.emitIRR(op, rsp, r13, 1);
      e.emitIRR(op, r14, r8, -128);
      e.emitIRR(op, r8, r15, -128);
      e.emitIRR(op, r13, r12, 127);
      e.emitIRR(op, r12, r13, 0xF1);
      e.emitIRR(op, r12, r13, 1);
      e.emitIRR(op, rax, rax, 1);
      e.emitIRR(op, rax, r8, 1);
      e.emitIRR(op, r8, rax, 1);
      e.emitIRR(op, r8, r8, 1);
    }

    if (supported_AM[i] & MASK_M) {
      printf("  Address mode: M\n");
      e.emitM(op, rsi, rdi, sz::word, -128);
      e.emitM(op, rbp, noreg, sz::dword, 127);
      e.emitM(op, noreg, rbp, sz::byte, 127);
      e.emitM(op, rsp, rbp, sz::qword, 0xF1);
      e.emitM(op, rsi, r15, sz::word, -128);
      e.emitM(op, rbp, noreg, sz::dword, 127);
      e.emitM(op, noreg, r13, sz::byte, 127);
      e.emitM(op, rsp, r13, sz::qword, 0xF1);
      e.emitM(op, r14, rdi, sz::word, -128);
      e.emitM(op, r13, noreg, sz::dword, 127);
      e.emitM(op, noreg, rbp, sz::byte, 127);
      e.emitM(op, r12, rbp, sz::qword, 0xF1);
      e.emitM(op, r14, r15, sz::word, -128);
      e.emitM(op, r13, noreg, sz::dword, 127);
      e.emitM(op, noreg, r13, sz::byte, 127);
      e.emitM(op, r12, r13, sz::qword, 0xF1);
      // Providing only an immediate with no base register and no index
      // register produces the RIP relative form
      e.emitM(op, noreg, noreg, sz::byte, 0xF1F1);
    }

    if (supported_AM[i] & MASK_RM) {
      printf("  Address mode: RM\n");
      e.emitRM(op, rsi, rdi, sz::word, -128, rax);
      e.emitRM(op, rbp, noreg, sz::dword, 127, rcx);
      e.emitRM(op, noreg, rbp, sz::byte, 127, rcx);
      e.emitRM(op, rsp, rbp, sz::qword, 0xF1, rbp);
      e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitRM(op, rsi, rdi, sz::word, -128, r8);
      e.emitRM(op, rbp, noreg, sz::dword, 127, r9);
      e.emitRM(op, noreg, rbp, sz::byte, 127, r9);
      e.emitRM(op, rsp, rbp, sz::qword, 0xF1, r13);
      e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, r12);
      e.emitRM(op, r14, rdi, sz::word, -128, rax);
      e.emitRM(op, r13, noreg, sz::dword, 127, rcx);
      e.emitRM(op, noreg, rbp, sz::byte, 127, rcx);
      e.emitRM(op, r12, rbp, sz::qword, 0xF1, rbp);
      e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitRM(op, r14, rdi, sz::word, -128, r8);
      e.emitRM(op, r13, noreg, sz::dword, 127, r9);
      e.emitRM(op, noreg, rbp, sz::byte, 127, r9);
      e.emitRM(op, r12, rbp, sz::qword, 0xF1, r13);
      e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, r12);
    }

    if (supported_AM[i] & MASK_MR) {
      printf("  Address mode: MR\n");
      e.emitMR(op, rsi, rdi, sz::word, -128, rax);
      e.emitMR(op, rbp, noreg, sz::dword, 127, rcx);
      e.emitMR(op, noreg, rbp, sz::byte, 127, rcx);
      e.emitMR(op, rsp, rbp, sz::qword, 0xF1, rbp);
      e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitMR(op, rsi, rdi, sz::word, -128, r8);
      e.emitMR(op, rbp, noreg, sz::dword, 127, r9);
      e.emitMR(op, noreg, rbp, sz::byte, 127, r9);
      e.emitMR(op, rsp, rbp, sz::qword, 0xF1, r13);
      e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, r12);
      e.emitMR(op, r14, rdi, sz::word, -128, rax);
      e.emitMR(op, r13, noreg, sz::dword, 127, rcx);
      e.emitMR(op, noreg, rbp, sz::byte, 127, rcx);
      e.emitMR(op, r12, rbp, sz::qword, 0xF1, rbp);
      e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitMR(op, r14, rdi, sz::word, -128, r8);
      e.emitMR(op, r13, noreg, sz::dword, 127, r9);
      e.emitMR(op, noreg, rbp, sz::byte, 127, r9);
      e.emitMR(op, r12, rbp, sz::qword, 0xF1, r13);
      e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, r12);
    }

    if (supported_AM[i] & MASK_IRM) {
      printf("  Address mode: IRM\n");
      e.emitIRM(op, rsi, rdi, sz::word, -128, rax, 0xF1F1F1F1);
      e.emitIRM(op, rbp, noreg, sz::dword, 127, rcx, 0xF1);
      e.emitIRM(op, noreg, rbp, sz::byte, 127, rcx, 0xF1);
      e.emitIRM(op, rsp, rbp, sz::qword, 0xF1, rbp, -128);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1);
      e.emitIRM(op, rsi, rdi, sz::word, -128, r8, 0xF1F1F1F1);
      e.emitIRM(op, rbp, noreg, sz::dword, 127, r9, 0xF1);
      e.emitIRM(op, noreg, rbp, sz::byte, 127, r9, 0xF1);
      e.emitIRM(op, rsp, rbp, sz::qword, 0xF1, r13, -128);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1);
      e.emitIRM(op, r14, rdi, sz::word, -128, rax, 0xF1F1F1F1);
      e.emitIRM(op, r13, noreg, sz::dword, 127, rcx, 0xF1);
      e.emitIRM(op, noreg, rbp, sz::byte, 127, rcx, 0xF1);
      e.emitIRM(op, r12, rbp, sz::qword, 0xF1, rbp, -128);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1);
      e.emitIRM(op, r14, rdi, sz::word, -128, r8, 0xF1F1F1F1);
      e.emitIRM(op, r13, noreg, sz::dword, 127, r9, 0xF1);
      e.emitIRM(op, noreg, rbp, sz::byte, 127, r9, 0xF1);
      e.emitIRM(op, r12, rbp, sz::qword, 0xF1, r13, -128);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127);
      e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1);
    }

    if (supported_AM[i] & MASK_IMR) {
      printf("  Address mode: IMR\n");
      e.emitIMR(op, rsi, rdi, sz::word, -128, rax, 0xF1F1F1F1);
      e.emitIMR(op, rbp, noreg, sz::dword, 127, rax, 0xF1);
      e.emitIMR(op, noreg, rbp, sz::byte, 127, rcx, 0xF1);
      e.emitIMR(op, rsp, rbp, sz::qword, 0xF1, rbp, -128);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1);
      e.emitIMR(op, rsi, rdi, sz::word, -128, r8, 0xF1F1F1F1);
      e.emitIMR(op, rbp, noreg, sz::dword, 127, r8, 0xF1);
      e.emitIMR(op, noreg, rbp, sz::byte, 127, r9, 0xF1);
      e.emitIMR(op, rsp, rbp, sz::qword, 0xF1, r13, -128);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1);
      e.emitIMR(op, r14, rdi, sz::word, -128, rax, 0xF1F1F1F1);
      e.emitIMR(op, r13, noreg, sz::dword, 127, rax, 0xF1);
      e.emitIMR(op, noreg, rbp, sz::byte, 127, rcx, 0xF1);
      e.emitIMR(op, r12, rbp, sz::qword, 0xF1, rbp, -128);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1);
      e.emitIMR(op, r14, rdi, sz::word, -128, r8, 0xF1F1F1F1);
      e.emitIMR(op, r13, noreg, sz::dword, 127, r8, 0xF1);
      e.emitIMR(op, noreg, rbp, sz::byte, 127, r9, 0xF1);
      e.emitIMR(op, r12, rbp, sz::qword, 0xF1, r13, -128);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127);
      e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1);
    }

    if (supported_AM[i] & MASK_IM) {
      printf("  Address mode: IM\n");
      e.emitIM(op, rsi, rdi, sz::word, -128, 0xF1F1F1F1);
      e.emitIM(op, rbp, noreg, sz::dword, 127, 0xF1);
      e.emitIM(op, noreg, rbp, sz::byte, 127, 0xF1);
      e.emitIM(op, rsp, rbp, sz::qword, 0xF1, -128);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1);
      e.emitIM(op, r14, rdi, sz::word, -128, 0xF1F1F1F1);
      e.emitIM(op, r13, noreg, sz::dword, 127, 0xF1);
      e.emitIM(op, noreg, rbp, sz::byte, 127, 0xF1);
      e.emitIM(op, r12, rbp, sz::qword, 0xF1, -128);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1);
      e.emitIM(op, rsi, r15, sz::word, -128, 0xF1F1F1F1);
      e.emitIM(op, rbp, noreg, sz::dword, 127, 0xF1);
      e.emitIM(op, noreg, r13, sz::byte, 127, 0xF1);
      e.emitIM(op, rsp, r13, sz::qword, 0xF1, -128);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127);
      e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1);
      if (i == 13 /*instr_mov*/) {
        e.emitIM(op, rsi, rdi, sz::word, -128, 0x1234123412341234);
        e.emitIM(op, r14, rdi, sz::word, -128, 0x1234123412341234);
        e.emitIM(op, rsi, r15, sz::word, -128, 0x1234123412341234);
      }
    }

    if (supported_AM[i] & MASK_CI) {
      printf("  Address mode: CI\n");
      e.emitCI(op, CC_NE, 0xF1F1F1F1);
      e.emitCI(op, CC_G, 0xF1);
      e.emitCI(op, CC_S, -128);
      e.emitCI(op, CC_O, 127);
      e.emitCI(op, CC_O, 1);
    }

    if (supported_AM[i] & MASK_CMR) {
      printf("  Address mode: CMR\n");
      e.emitCMR(op, CC_NE, rsi, rdi, sz::word, -128, rax);
      e.emitCMR(op, CC_G, rbp, noreg, sz::dword, 127, rcx);
      e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, rcx);
      e.emitCMR(op, CC_S, rsp, rbp, sz::qword, 0xF1, rbp);
      e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitCMR(op, CC_NE, rsi, rdi, sz::word, -128, r8);
      e.emitCMR(op, CC_G, rbp, noreg, sz::dword, 127, r9);
      e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, r9);
      e.emitCMR(op, CC_S, rsp, rbp, sz::qword, 0xF1, r13);
      e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, r12);
      e.emitCMR(op, CC_NE, r14, rdi, sz::word, -128, rax);
      e.emitCMR(op, CC_G, r13, noreg, sz::dword, 127, rcx);
      e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, rcx);
      e.emitCMR(op, CC_S, r12, rbp, sz::qword, 0xF1, rbp);
      e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, rsp);
      e.emitCMR(op, CC_NE, r14, rdi, sz::word, -128, r8);
      e.emitCMR(op, CC_G, r12, noreg, sz::dword, 127, r9);
      e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, r9);
      e.emitCMR(op, CC_S, r12, rbp, sz::qword, 0xF1, r13);
      e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, r12);
    }

    if (supported_AM[i] & MASK_CR) {
      printf("  Address mode: CR\n");
      e.emitCR(op, CC_NE, rax);
      e.emitCR(op, CC_G, rcx);
      e.emitCR(op, CC_S, rbp);
      e.emitCR(op, CC_O, rsp);
      e.emitCR(op, CC_NE, r8);
      e.emitCR(op, CC_G, r9);
      e.emitCR(op, CC_S, r13);
      e.emitCR(op, CC_O, r12);
    }

    if (supported_AM[i] & MASK_CM) {
      printf("  Address mode: CM\n");
      e.emitCM(op, CC_NE, rsi, rdi, sz::word, -128);
      e.emitCM(op, CC_G, rbp, noreg, sz::dword, 127);
      e.emitCM(op, CC_G, noreg, rbp, sz::byte, 127);
      e.emitCM(op, CC_S, rsp, rbp, sz::qword, 0xF1);
      e.emitCM(op, CC_S, rbp, rbp, sz::qword, 0xF1);
      e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1);
      e.emitCM(op, CC_NE, rsi, r15, sz::word, -128);
      e.emitCM(op, CC_G, rbp, noreg, sz::dword, 127);
      e.emitCM(op, CC_G, noreg, r13, sz::byte, 127);
      e.emitCM(op, CC_S, rsp, r13, sz::qword, 0xF1);
      e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1);
      e.emitCM(op, CC_NE, r14, rdi, sz::word, -128);
      e.emitCM(op, CC_G, r13, noreg, sz::dword, 127);
      e.emitCM(op, CC_G, noreg, rbp, sz::byte, 127);
      e.emitCM(op, CC_S, r12, rbp, sz::qword, 0xF1);
      e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1);
      e.emitCM(op, CC_NE, r14, r15, sz::word, -128);
      e.emitCM(op, CC_G, r13, noreg, sz::dword, 127);
      e.emitCM(op, CC_G, noreg, r13, sz::byte, 127);
      e.emitCM(op, CC_S, r12, r13, sz::qword, 0xF1);
      e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1);
    }

    if (supported_AM[i] & MASK_CRR) {
      printf("  Address mode: CRR\n");
      e.emitCRR(op, CC_NE, rsi, rax);
      e.emitCRR(op, CC_G, rax, rdi);
      e.emitCRR(op, CC_S, rsi, rdi);
      e.emitCRR(op, CC_O, rbp, rsp);
      e.emitCRR(op, CC_E, rsp, rbp);
      e.emitCRR(op, CC_NP, rsi, r8);
      e.emitCRR(op, CC_P, rax, r15);
      e.emitCRR(op, CC_L, rsi, r15);
      e.emitCRR(op, CC_LE, rbp, r12);
      e.emitCRR(op, CC_BE, rsp, r13);
      e.emitCRR(op, CC_NO, r14, rax);
      e.emitCRR(op, CC_NS, r8, rdi);
      e.emitCRR(op, CC_NE, r14, rdi);
      e.emitCRR(op, CC_G, r13, rsp);
      e.emitCRR(op, CC_S, r12, rbp);
      e.emitCRR(op, CC_O, r14, r8);
      e.emitCRR(op, CC_E, r8, r15);
      e.emitCRR(op, CC_NP, r14, r15);
      e.emitCRR(op, CC_P, r13, r12);
      e.emitCRR(op, CC_L, r12, r13);
      e.emitCRR(op, CC_LE, rax, rax);
      e.emitCRR(op, CC_BE, rax, r8);
      e.emitCRR(op, CC_NO, r8, rax);
      e.emitCRR(op, CC_NS, r8, r8);
    }
    printf("\n");
  }
}