extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_reg(Mnemonic m, OpndSize size,
                   int imm, int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    EncoderBase::Operands args;
    add_r(args, reg, size); //dst
    if(m == Mnemonic_IMUL) add_r(args, reg, size); //src CHECK
    if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
       || m == Mnemonic_SAR || m == Mnemonic_ROR)  //fix for shift opcodes
      add_imm(args, OpndSize_8, imm, true/*is_signed*/);
    else
      add_imm(args, size, imm, true/*is_signed*/);
    char* stream_start = stream;
    stream = (char *)EncoderBase::encode(stream, m, args);
#ifdef PRINT_ENCODER_STREAM
    printEncoderInst(m, args);
    decodeThenPrint(stream_start);
#endif
    return stream;
}
extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm(Mnemonic m, OpndSize size, int imm, char * stream) {
    EncoderBase::Operands args;
    //assert(imm.get_size() == size_32);
    add_imm(args, size, imm, true/*is_signed*/);
    char* stream_start = stream;
    stream = (char *)EncoderBase::encode(stream, m, args);
#ifdef PRINT_ENCODER_STREAM
    printEncoderInst(m, args);
    decodeThenPrint(stream_start);
#endif
    return stream;
}
extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream) {
    Inst decInst;
    unsigned numBytes = DecoderBase::decode(stream, &decInst);
    EncoderBase::Operands args;
    args.add(decInst.operands[0]);
    add_imm(args, decInst.operands[1].size(), imm, true/*is_signed*/);
    char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
#ifdef PRINT_ENCODER_STREAM
    printEncoderInst(decInst.mn, args);
    decodeThenPrint(stream);
#endif
    return stream_next;
}
extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_mem(Mnemonic m, OpndSize size,
                   int imm,
                   int disp, int base_reg, bool isBasePhysical, char * stream) {
    EncoderBase::Operands args;
    add_m(args, base_reg, disp, size);
    if (m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
        || m == Mnemonic_SAR || m == Mnemonic_ROR)
        size = OpndSize_8;
    add_imm(args, size, imm, true);
    char* stream_start = stream;
    stream = (char *)EncoderBase::encode(stream, m, args);
#ifdef PRINT_ENCODER_STREAM
    printEncoderInst(m, args);
    decodeThenPrint(stream_start);
#endif
    return stream;
}
void InterpreterStubs::generate_interpreter_fill_in_tags() {
  Segment seg(this, code_segment, "Interpreter fill in tags");

  Register param_size = tmp0; // must be preserved
  Register callinfo   = tmp1;

  {
      bind_local("interpreter_fill_in_tags");
      comment("%s: size of parameters",       reg_name(tmp0));
      comment("%s: call info from call size", reg_name(tmp1));
      comment("");
      comment("Must preserve lr, %s (method), and %s (parameter size)", 
              reg_name(r0), reg_name(tmp0));

      Label loop_entry;

      // tos_val = r0 must be preserved
      Register arg_index  = tmp2;
      Register one_reg    = tmp3;
      Register tag_address = JavaStackDirection < 0 ? tmp4 : jsp;

      mov_imm(one_reg, 1 << CallInfo::format1_tag_start);
      sub(arg_index, param_size, one, set_CC);
      report_fatal("shouldn't be called on no arguments", lt);

      if (JavaStackDirection < 0) { 
        comment("Tag address of last argument");
        add(tag_address, jsp, imm(BytesPerWord));
      } else { 
        comment("jsp points to tag address of last argument");
      }

    bind(loop_entry);
      comment("test the bit in the call info");
      tst(callinfo, reg_shift(one_reg, lsl, arg_index));

      mov(tos_tag, imm(obj_tag), ne);
      mov(tos_tag, imm(int_tag), eq);
      if (JavaStackDirection < 0) { 
        str(tos_tag, add_index(tag_address, arg_index, lsl, 3));
      } else {
        str(tos_tag, sub_index(tag_address, arg_index, lsl, 3));
      }
      sub(arg_index, arg_index, one, set_CC);
      b(loop_entry, ge);
      mov(pc, reg(locals));
  }
  {
    Register bit_offset  = tmp1; // callinfo not needed
    Register one_reg     = tmp2;
    Register tag_address = tmp3;
    Register x1          = tmp4;
    Register x2          = tmp5;
    Register index       = tos_tag;
    Label loop;

    bind_local("interpreter_fill_in_extended_tags");
       comment("Total number of tags");
       if (HARDWARE_LITTLE_ENDIAN) {
         ldrh(bit_offset, imm_index3(lr, -2 * BytesPerWord));
       } else {
         ldrh(bit_offset, imm_index3(lr, -2 * BytesPerWord + 2));
       }

       comment("Tag address of first argument");
       if (JavaStackDirection < 0) {
         add(tag_address, jsp, imm_shift(param_size, lsl, 3));
       } else { 
         sub(tag_address, jsp, imm_shift(param_size, lsl, 3));
       }
       // tag_address points to the last address of the previous stack
       add_imm(tag_address, tag_address,
               JavaFrame::arg_offset_from_sp(-1) + BytesPerWord);

       comment("Index of last argument");
       sub(index, param_size, one);    

       comment("Bit number of first argument");
       sub(bit_offset, bit_offset, reg(param_size));
       mov(bit_offset, imm_shift(bit_offset, lsl, 2));
       add(bit_offset, bit_offset, imm(32 + 32 + 16));

       comment("A useful constant");
       mov(one_reg, one);

    bind(loop);
       comment("Get the bit offset for this argument");
       add(x1, bit_offset, imm_shift(index, lsl, 2));

       comment("Get the appropriate word");
       mov(x2, imm_shift(x1, lsr, 5));
       ldr(x2, sub_index(lr, x2, lsl, 2));

       comment("Pick out the nybble");
       andr(x1, x1, imm(31));
       mov(x2, reg_shift(x2, lsr, x1));
       andr(x2, x2, imm(15), set_CC);

       comment("Convert the nybble into a stack type");
       sub(x2, x2, one,                     ne);
       mov(x2, reg_shift(one_reg, lsl, x2), ne);
       if (JavaStackDirection < 0) {
         str(x2, sub_index(tag_address, index, lsl, 3));
       } else {
         str(x2, add_index(tag_address, index, lsl, 3));
       }
       comment("Update the info");
       sub(index, index, one, set_CC);
       b(loop, ge);
       mov(pc, reg(locals));
  }
}