text: // Copyright 2014 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  // A Disassembler object is used to disassemble a block of code instruction by
  // instruction. The default implementation of the NameConverter object can be
  // overriden to modify register names or to do symbol lookup on addresses.
  //
  // The example below will disassemble a block of code and print it to stdout.
  //
  //   NameConverter converter;
  //   Disassembler d(converter);
  //   for (byte* pc = begin; pc < end;) {
  //     v8::internal::EmbeddedVector<char, 256> buffer;
  //     byte* prev_pc = pc;
  //     pc += d.InstructionDecode(buffer, pc);
  //     printf("%p    %08x      %s\n",
  //            prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
  //   }
  //
  // The Disassembler class also has a convenience method to disassemble a block
  // of code into a FILE*, meaning that the above functionality could also be
  // achieved by just calling Disassembler::Disassemble(stdout, begin, end);
  
  #include <assert.h>
  #include <stdarg.h>
  #include <stdio.h>
  #include <string.h>
  
  #if V8_TARGET_ARCH_S390
  
  #include "src/base/platform/platform.h"
  #include "src/disasm.h"
  #include "src/macro-assembler.h"
  #include "src/s390/constants-s390.h"
  
  namespace v8 {
  namespace internal {
  
  const auto GetRegConfig = RegisterConfiguration::Crankshaft;
  
  //------------------------------------------------------------------------------
  
  // Decoder decodes and disassembles instructions into an output buffer.
  // It uses the converter to convert register names and call destinations into
  // more informative description.
  class Decoder {
   public:
    Decoder(const disasm::NameConverter& converter, Vector<char> out_buffer)
        : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) {
      out_buffer_[out_buffer_pos_] = '\0';
    }
  
    ~Decoder() {}
  
    // Writes one disassembled instruction into 'buffer' (0-terminated).
    // Returns the length of the disassembled machine instruction in bytes.
    int InstructionDecode(byte* instruction);
  
   private:
    // Bottleneck functions to print into the out_buffer.
    void PrintChar(const char ch);
    void Print(const char* str);
  
    // Printing of common values.
    void PrintRegister(int reg);
    void PrintDRegister(int reg);
    void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
  
    // Handle formatting of instructions and their options.
    int FormatRegister(Instruction* instr, const char* option);
    int FormatFloatingRegister(Instruction* instr, const char* option);
    int FormatMask(Instruction* instr, const char* option);
    int FormatDisplacement(Instruction* instr, const char* option);
    int FormatImmediate(Instruction* instr, const char* option);
    int FormatOption(Instruction* instr, const char* option);
    void Format(Instruction* instr, const char* format);
    void Unknown(Instruction* instr);
    void UnknownFormat(Instruction* instr, const char* opcname);
  
    bool DecodeTwoByte(Instruction* instr);
    bool DecodeFourByte(Instruction* instr);
    bool DecodeSixByte(Instruction* instr);
  
    const disasm::NameConverter& converter_;
    Vector<char> out_buffer_;
    int out_buffer_pos_;
  
    DISALLOW_COPY_AND_ASSIGN(Decoder);
  };
  
  // Support for assertions in the Decoder formatting functions.
  #define STRING_STARTS_WITH(string, compare_string) \
    (strncmp(string, compare_string, strlen(compare_string)) == 0)
  
  // Append the ch to the output buffer.
  void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; }
  
  // Append the str to the output buffer.
  void Decoder::Print(const char* str) {
    char cur = *str++;
    while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
      PrintChar(cur);
      cur = *str++;
    }
    out_buffer_[out_buffer_pos_] = 0;
  }
  
  // Print the register name according to the active name converter.
  void Decoder::PrintRegister(int reg) {
    Print(converter_.NameOfCPURegister(reg));
  }
  
  // Print the double FP register name according to the active name converter.
  void Decoder::PrintDRegister(int reg) {
    Print(GetRegConfig()->GetDoubleRegisterName(reg));
  }
  
  // Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
  // the FormatOption method.
  void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
    switch (svc) {
      case kCallRtRedirected:
        Print("call rt redirected");
        return;
      case kBreakpoint:
        Print("breakpoint");
        return;
      default:
        if (svc >= kStopCode) {
          out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d - 0x%x",
                                      svc & kStopCodeMask, svc & kStopCodeMask);
        } else {
          out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", svc);
        }
        return;
    }
  }
  
  // Handle all register based formatting in this function to reduce the
  // complexity of FormatOption.
  int Decoder::FormatRegister(Instruction* instr, const char* format) {
    DCHECK(format[0] == 'r');
  
    if (format[1] == '1') {  // 'r1: register resides in bit 8-11
      RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
      int reg = rrinstr->R1Value();
      PrintRegister(reg);
      return 2;
    } else if (format[1] == '2') {  // 'r2: register resides in bit 12-15
      RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
      int reg = rrinstr->R2Value();
      // indicating it is a r0 for displacement, in which case the offset
      // should be 0.
      if (format[2] == 'd') {
        if (reg == 0) return 4;
        PrintRegister(reg);
        return 3;
      } else {
        PrintRegister(reg);
        return 2;
      }
    } else if (format[1] == '3') {  // 'r3: register resides in bit 16-19
      RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
      int reg = rsinstr->B2Value();
      PrintRegister(reg);
      return 2;
    } else if (format[1] == '4') {  // 'r4: register resides in bit 20-23
      RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
      int reg = rsinstr->B2Value();
      PrintRegister(reg);
      return 2;
    } else if (format[1] == '5') {  // 'r5: register resides in bit 24-28
      RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
      int reg = rreinstr->R1Value();
      PrintRegister(reg);
      return 2;
    } else if (format[1] == '6') {  // 'r6: register resides in bit 29-32
      RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
      int reg = rreinstr->R2Value();
      PrintRegister(reg);
      return 2;
    } else if (format[1] == '7') {  // 'r6: register resides in bit 32-35
      SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
      int reg = ssinstr->B2Value();
      PrintRegister(reg);
      return 2;
    }
  
    UNREACHABLE();
    return -1;
  }
  
  int Decoder::FormatFloatingRegister(Instruction* instr, const char* format) {
    DCHECK(format[0] == 'f');
  
    // reuse 1, 5 and 6 because it is coresponding
    if (format[1] == '1') {  // 'r1: register resides in bit 8-11
      RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
      int reg = rrinstr->R1Value();
      PrintDRegister(reg);
      return 2;
    } else if (format[1] == '2') {  // 'f2: register resides in bit 12-15
      RRInstruction* rrinstr = reinterpret_cast<RRInstruction*>(instr);
      int reg = rrinstr->R2Value();
      PrintDRegister(reg);
      return 2;
    } else if (format[1] == '3') {  // 'f3: register resides in bit 16-19
      RRDInstruction* rrdinstr = reinterpret_cast<RRDInstruction*>(instr);
      int reg = rrdinstr->R1Value();
      PrintDRegister(reg);
      return 2;
    } else if (format[1] == '5') {  // 'f5: register resides in bit 24-28
      RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
      int reg = rreinstr->R1Value();
      PrintDRegister(reg);
      return 2;
    } else if (format[1] == '6') {  // 'f6: register resides in bit 29-32
      RREInstruction* rreinstr = reinterpret_cast<RREInstruction*>(instr);
      int reg = rreinstr->R2Value();
      PrintDRegister(reg);
      return 2;
    }
    UNREACHABLE();
    return -1;
  }
  
  // FormatOption takes a formatting string and interprets it based on
  // the current instructions. The format string points to the first
  // character of the option string (the option escape has already been
  // consumed by the caller.)  FormatOption returns the number of
  // characters that were consumed from the formatting string.
  int Decoder::FormatOption(Instruction* instr, const char* format) {
    switch (format[0]) {
      case 'o': {
        if (instr->Bit(10) == 1) {
          Print("o");
        }
        return 1;
      }
      case '.': {
        if (instr->Bit(0) == 1) {
          Print(".");
        } else {
          Print(" ");  // ensure consistent spacing
        }
        return 1;
      }
      case 'r': {
        return FormatRegister(instr, format);
      }
      case 'f': {
        return FormatFloatingRegister(instr, format);
      }
      case 'i': {  // int16
        return FormatImmediate(instr, format);
      }
      case 'u': {  // uint16
        int32_t value = instr->Bits(15, 0);
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
        return 6;
      }
      case 'l': {
        // Link (LK) Bit 0
        if (instr->Bit(0) == 1) {
          Print("l");
        }
        return 1;
      }
      case 'a': {
        // Absolute Address Bit 1
        if (instr->Bit(1) == 1) {
          Print("a");
        }
        return 1;
      }
      case 't': {  // 'target: target of branch instructions
        // target26 or target16
        DCHECK(STRING_STARTS_WITH(format, "target"));
        if ((format[6] == '2') && (format[7] == '6')) {
          int off = ((instr->Bits(25, 2)) << 8) >> 6;
          out_buffer_pos_ += SNPrintF(
              out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
              converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
          return 8;
        } else if ((format[6] == '1') && (format[7] == '6')) {
          int off = ((instr->Bits(15, 2)) << 18) >> 16;
          out_buffer_pos_ += SNPrintF(
              out_buffer_ + out_buffer_pos_, "%+d -> %s", off,
              converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
          return 8;
        }
        case 'm': {
          return FormatMask(instr, format);
        }
      }
      case 'd': {  // ds value for offset
        return FormatDisplacement(instr, format);
      }
      default: {
        UNREACHABLE();
        break;
      }
    }
  
    UNREACHABLE();
    return -1;
  }
  
  int Decoder::FormatMask(Instruction* instr, const char* format) {
    DCHECK(format[0] == 'm');
    int32_t value = 0;
    if ((format[1] == '1')) {  // prints the mask format in bits 8-12
      value = reinterpret_cast<RRInstruction*>(instr)->R1Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
      return 2;
    } else if (format[1] == '2') {  // mask format in bits 16-19
      value = reinterpret_cast<RXInstruction*>(instr)->B2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
      return 2;
    } else if (format[1] == '3') {  // mask format in bits 20-23
      value = reinterpret_cast<RRFInstruction*>(instr)->M4Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", value);
      return 2;
    }
  
    out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
    return 2;
  }
  
  int Decoder::FormatDisplacement(Instruction* instr, const char* format) {
    DCHECK(format[0] == 'd');
  
    if (format[1] == '1') {  // displacement in 20-31
      RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
      uint16_t value = rsinstr->D2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
  
      return 2;
    } else if (format[1] == '2') {  // displacement in 20-39
      RXYInstruction* rxyinstr = reinterpret_cast<RXYInstruction*>(instr);
      int32_t value = rxyinstr->D2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '4') {  // SS displacement 2 36-47
      SSInstruction* ssInstr = reinterpret_cast<SSInstruction*>(instr);
      uint16_t value = ssInstr->D2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '3') {  // SS displacement 1 20 - 32
      SSInstruction* ssInstr = reinterpret_cast<SSInstruction*>(instr);
      uint16_t value = ssInstr->D1Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else {  // s390 specific
      int32_t value = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 1;
    }
  }
  
  int Decoder::FormatImmediate(Instruction* instr, const char* format) {
    DCHECK(format[0] == 'i');
  
    if (format[1] == '1') {  // immediate in 16-31
      RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
      int16_t value = riinstr->I2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '2') {  // immediate in 16-48
      RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
      int32_t value = rilinstr->I2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '3') {  // immediate in I format
      IInstruction* iinstr = reinterpret_cast<IInstruction*>(instr);
      int8_t value = iinstr->IValue();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '4') {  // immediate in 16-31, but outputs as offset
      RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
      int16_t value = riinstr->I2Value() * 2;
      if (value >= 0)
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
      else
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
  
      out_buffer_pos_ += SNPrintF(
          out_buffer_ + out_buffer_pos_, "%d -> %s", value,
          converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
      return 2;
    } else if (format[1] == '5') {  // immediate in 16-31, but outputs as offset
      RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
      int32_t value = rilinstr->I2Value() * 2;
      if (value >= 0)
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
      else
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
  
      out_buffer_pos_ += SNPrintF(
          out_buffer_ + out_buffer_pos_, "%d -> %s", value,
          converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
      return 2;
    } else if (format[1] == '6') {  // unsigned immediate in 16-31
      RIInstruction* riinstr = reinterpret_cast<RIInstruction*>(instr);
      uint16_t value = riinstr->I2UnsignedValue();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '7') {  // unsigned immediate in 16-47
      RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
      uint32_t value = rilinstr->I2UnsignedValue();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '8') {  // unsigned immediate in 8-15
      SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
      uint8_t value = ssinstr->Length();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == '9') {  // unsigned immediate in 16-23
      RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
      uint8_t value = rie_instr->I3Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == 'a') {  // unsigned immediate in 24-31
      RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
      uint8_t value = rie_instr->I4Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == 'b') {  // unsigned immediate in 32-39
      RIEInstruction* rie_instr = reinterpret_cast<RIEInstruction*>(instr);
      uint8_t value = rie_instr->I5Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == 'c') {  // signed immediate in 8-15
      SSInstruction* ssinstr = reinterpret_cast<SSInstruction*>(instr);
      int8_t value = ssinstr->Length();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == 'd') {  // signed immediate in 32-47
      SILInstruction* silinstr = reinterpret_cast<SILInstruction*>(instr);
      int16_t value = silinstr->I2Value();
      out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", value);
      return 2;
    } else if (format[1] == 'e') {  // immediate in 16-47, but outputs as offset
      RILInstruction* rilinstr = reinterpret_cast<RILInstruction*>(instr);
      int32_t value = rilinstr->I2Value() * 2;
      if (value >= 0)
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*+");
      else
        out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "*");
  
      out_buffer_pos_ += SNPrintF(
          out_buffer_ + out_buffer_pos_, "%d -> %s", value,
          converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + value));
      return 2;
    }
  
    UNREACHABLE();
    return -1;
  }
  
  // Format takes a formatting string for a whole instruction and prints it into
  // the output buffer. All escaped options are handed to FormatOption to be
  // parsed further.
  void Decoder::Format(Instruction* instr, const char* format) {
    char cur = *format++;
    while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
      if (cur == '\'') {  // Single quote is used as the formatting escape.
        format += FormatOption(instr, format);
      } else {
        out_buffer_[out_buffer_pos_++] = cur;
      }
      cur = *format++;
    }
    out_buffer_[out_buffer_pos_] = '\0';
  }
  
  // The disassembler may end up decoding data inlined in the code. We do not want
  // it to crash if the data does not ressemble any known instruction.
  #define VERIFY(condition) \
    if (!(condition)) {     \
      Unknown(instr);       \
      return;               \
    }
  
  // For currently unimplemented decodings the disassembler calls Unknown(instr)
  // which will just print "unknown" of the instruction bits.
  void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); }
  
  // For currently unimplemented decodings the disassembler calls
  // UnknownFormat(instr) which will just print opcode name of the
  // instruction bits.
  void Decoder::UnknownFormat(Instruction* instr, const char* name) {
    char buffer[100];
    snprintf(buffer, sizeof(buffer), "%s (unknown-format)", name);
    Format(instr, buffer);
  }
  
  // Disassembles Two Byte S390 Instructions
  // @return true if successfully decoded
  bool Decoder::DecodeTwoByte(Instruction* instr) {
    // Print the Instruction bits.
    out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%04x           ",
                                instr->InstructionBits<TwoByteInstr>());
  
    Opcode opcode = instr->S390OpcodeValue();
    switch (opcode) {
      case AR:
        Format(instr, "ar\t'r1,'r2");
        break;
      case SR:
        Format(instr, "sr\t'r1,'r2");
        break;
      case MR:
        Format(instr, "mr\t'r1,'r2");
        break;
      case DR:
        Format(instr, "dr\t'r1,'r2");
        break;
      case OR:
        Format(instr, "or\t'r1,'r2");
        break;
      case NR:
        Format(instr, "nr\t'r1,'r2");
        break;
      case XR:
        Format(instr, "xr\t'r1,'r2");
        break;
      case LR:
        Format(instr, "lr\t'r1,'r2");
        break;
      case CR:
        Format(instr, "cr\t'r1,'r2");
        break;
      case CLR:
        Format(instr, "clr\t'r1,'r2");
        break;
      case BCR:
        Format(instr, "bcr\t'm1,'r2");
        break;
      case LTR:
        Format(instr, "ltr\t'r1,'r2");
        break;
      case ALR:
        Format(instr, "alr\t'r1,'r2");
        break;
      case SLR:
        Format(instr, "slr\t'r1,'r2");
        break;
      case LNR:
        Format(instr, "lnr\t'r1,'r2");
        break;
      case LCR:
        Format(instr, "lcr\t'r1,'r2");
        break;
      case BASR:
        Format(instr, "basr\t'r1,'r2");
        break;
      case LDR:
        Format(instr, "ldr\t'f1,'f2");
        break;
      case BKPT:
        Format(instr, "bkpt");
        break;
      case LPR:
        Format(instr, "lpr\t'r1, 'r2");
        break;
      default:
        return false;
    }
    return true;
  }
  
  // Disassembles Four Byte S390 Instructions
  // @return true if successfully decoded
  bool Decoder::DecodeFourByte(Instruction* instr) {
    // Print the Instruction bits.
    out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%08x       ",
                                instr->InstructionBits<FourByteInstr>());
  
    Opcode opcode = instr->S390OpcodeValue();
    switch (opcode) {
      case AHI:
        Format(instr, "ahi\t'r1,'i1");
        break;
      case AGHI:
        Format(instr, "aghi\t'r1,'i1");
        break;
      case LHI:
        Format(instr, "lhi\t'r1,'i1");
        break;
      case LGHI:
        Format(instr, "lghi\t'r1,'i1");
        break;
      case MHI:
        Format(instr, "mhi\t'r1,'i1");
        break;
      case MGHI:
        Format(instr, "mghi\t'r1,'i1");
        break;
      case CHI:
        Format(instr, "chi\t'r1,'i1");
        break;
      case CGHI:
        Format(instr, "cghi\t'r1,'i1");
        break;
      case BRAS:
        Format(instr, "bras\t'r1,'i1");
        break;
      case BRC:
        Format(instr, "brc\t'm1,'i4");
        break;
      case BRCT:
        Format(instr, "brct\t'r1,'i4");
        break;
      case BRCTG:
        Format(instr, "brctg\t'r1,'i4");
        break;
      case IIHH:
        Format(instr, "iihh\t'r1,'i1");
        break;
      case IIHL:
        Format(instr, "iihl\t'r1,'i1");
        break;
      case IILH:
        Format(instr, "iilh\t'r1,'i1");
        break;
      case IILL:
        Format(instr, "iill\t'r1,'i1");
        break;
      case OILL:
        Format(instr, "oill\t'r1,'i1");
        break;
      case TMLL:
        Format(instr, "tmll\t'r1,'i1");
        break;
      case STM:
        Format(instr, "stm\t'r1,'r2,'d1('r3)");
        break;
      case LM:
        Format(instr, "lm\t'r1,'r2,'d1('r3)");
        break;
      case SLL:
        Format(instr, "sll\t'r1,'d1('r3)");
        break;
      case SRL:
        Format(instr, "srl\t'r1,'d1('r3)");
        break;
      case SLA:
        Format(instr, "sla\t'r1,'d1('r3)");
        break;
      case SRA:
        Format(instr, "sra\t'r1,'d1('r3)");
        break;
      case SLDL:
        Format(instr, "sldl\t'r1,'d1('r3)");
        break;
      case AGR:
        Format(instr, "agr\t'r5,'r6");
        break;
      case AGFR:
        Format(instr, "agfr\t'r5,'r6");
        break;
      case ARK:
        Format(instr, "ark\t'r5,'r6,'r3");
        break;
      case AGRK:
        Format(instr, "agrk\t'r5,'r6,'r3");
        break;
      case SGR:
        Format(instr, "sgr\t'r5,'r6");
        break;
      case SGFR:
        Format(instr, "sgfr\t'r5,'r6");
        break;
      case SRK:
        Format(instr, "srk\t'r5,'r6,'r3");
        break;
      case SGRK:
        Format(instr, "sgrk\t'r5,'r6,'r3");
        break;
      case NGR:
        Format(instr, "ngr\t'r5,'r6");
        break;
      case NRK:
        Format(instr, "nrk\t'r5,'r6,'r3");
        break;
      case NGRK:
        Format(instr, "ngrk\t'r5,'r6,'r3");
        break;
      case NILL:
        Format(instr, "nill\t'r1,'i1");
        break;
      case NILH:
        Format(instr, "nilh\t'r1,'i1");
        break;
      case OGR:
        Format(instr, "ogr\t'r5,'r6");
        break;
      case ORK:
        Format(instr, "ork\t'r5,'r6,'r3");
        break;
      case OGRK:
        Format(instr, "ogrk\t'r5,'r6,'r3");
        break;
      case XGR:
        Format(instr, "xgr\t'r5,'r6");
        break;
      case XRK:
        Format(instr, "xrk\t'r5,'r6,'r3");
        break;
      case XGRK:
        Format(instr, "xgrk\t'r5,'r6,'r3");
        break;
      case CGFR:
        Format(instr, "cgfr\t'r5,'r6");
        break;
      case CGR:
        Format(instr, "cgr\t'r5,'r6");
        break;
      case CLGR:
        Format(instr, "clgr\t'r5,'r6");
        break;
      case LLGFR:
        Format(instr, "llgfr\t'r5,'r6");
        break;
      case POPCNT_Z:
        Format(instr, "popcnt\t'r5,'r6");
        break;
      case LLGCR:
        Format(instr, "llgcr\t'r5,'r6");
        break;
      case LLCR:
        Format(instr, "llcr\t'r5,'r6");
        break;
      case LBR:
        Format(instr, "lbr\t'r5,'r6");
        break;
      case LEDBR:
        Format(instr, "ledbr\t'f5,'f6");
        break;
      case LDEBR:
        Format(instr, "ldebr\t'f5,'f6");
        break;
      case LTGR:
        Format(instr, "ltgr\t'r5,'r6");
        break;
      case LTDBR:
        Format(instr, "ltdbr\t'f5,'f6");
        break;
      case LTEBR:
        Format(instr, "ltebr\t'f5,'f6");
        break;
      case LRVR:
        Format(instr, "lrvr\t'r5,'r6");
        break;
      case LRVGR:
        Format(instr, "lrvgr\t'r5,'r6");
        break;
      case LGR:
        Format(instr, "lgr\t'r5,'r6");
        break;
      case LGDR:
        Format(instr, "lgdr\t'r5,'f6");
        break;
      case LGFR:
        Format(instr, "lgfr\t'r5,'r6");
        break;
      case LTGFR:
        Format(instr, "ltgfr\t'r5,'r6");
        break;
      case LCGR:
        Format(instr, "lcgr\t'r5,'r6");
        break;
      case MSR:
        Format(instr, "msr\t'r5,'r6");
        break;
      case MSRKC:
        Format(instr, "msrkc\t'r5,'r6,'r3");
        break;
      case LGBR:
        Format(instr, "lgbr\t'r5,'r6");
        break;
      case LGHR:
        Format(instr, "lghr\t'r5,'r6");
        break;
      case MSGR:
        Format(instr, "msgr\t'r5,'r6");
        break;
      case MSGRKC:
        Format(instr, "msgrkc\t'r5,'r6,'r3");
        break;
      case DSGR:
        Format(instr, "dsgr\t'r5,'r6");
        break;
      case DSGFR:
        Format(instr, "dsgfr\t'r5,'r6");
        break;
      case MSGFR:
        Format(instr, "msgfr\t'r5,'r6");
        break;
      case LZDR:
        Format(instr, "lzdr\t'f5");
        break;
      case MLR:
        Format(instr, "mlr\t'r5,'r6");
        break;
      case MLGR:
        Format(instr, "mlgr\t'r5,'r6");
        break;
      case ALCR:
        Format(instr, "alcr\t'r5,'r6");
        break;
      case ALGR:
        Format(instr, "algr\t'r5,'r6");
        break;
      case ALRK:
        Format(instr, "alrk\t'r5,'r6,'r3");
        break;
      case ALGRK:
        Format(instr, "algrk\t'r5,'r6,'r3");
        break;
      case SLGR:
        Format(instr, "slgr\t'r5,'r6");
        break;
      case SLBR:
        Format(instr, "slbr\t'r5,'r6");
        break;
      case DLR:
        Format(instr, "dlr\t'r5,'r6");
        break;
      case DLGR:
        Format(instr, "dlgr\t'r5,'r6");
        break;
      case SLRK:
        Format(instr, "slrk\t'r5,'r6,'r3");
        break;
      case SLGRK:
        Format(instr, "slgrk\t'r5,'r6,'r3");
        break;
      case LHR:
        Format(instr, "lhr\t'r5,'r6");
        break;
      case LLHR:
        Format(instr, "llhr\t'r5,'r6");
        break;
      case LLGHR:
        Format(instr, "llghr\t'r5,'r6");
        break;
      case LOCR:
        Format(instr, "locr\t'm1,'r5,'r6");
        break;
      case LOCGR:
        Format(instr, "locgr\t'm1,'r5,'r6");
        break;
      case LNGR:
        Format(instr, "lngr\t'r5,'r6");
        break;
      case A:
        Format(instr, "a\t'r1,'d1('r2d,'r3)");
        break;
      case S:
        Format(instr, "s\t'r1,'d1('r2d,'r3)");
        break;
      case M:
        Format(instr, "m\t'r1,'d1('r2d,'r3)");
        break;
      case D:
        Format(instr, "d\t'r1,'d1('r2d,'r3)");
        break;
      case O:
        Format(instr, "o\t'r1,'d1('r2d,'r3)");
        break;
      case N:
        Format(instr, "n\t'r1,'d1('r2d,'r3)");
        break;
      case L:
        Format(instr, "l\t'r1,'d1('r2d,'r3)");
        break;
      case C:
        Format(instr, "c\t'r1,'d1('r2d,'r3)");
        break;
      case AH:
        Format(instr, "ah\t'r1,'d1('r2d,'r3)");
        break;
      case SH:
        Format(instr, "sh\t'r1,'d1('r2d,'r3)");
        break;
      case MH:
        Format(instr, "mh\t'r1,'d1('r2d,'r3)");
        break;
      case AL:
        Format(instr, "al\t'r1,'d1('r2d,'r3)");
        break;
      case SL:
        Format(instr, "sl\t'r1,'d1('r2d,'r3)");
        break;
      case LA:
        Format(instr, "la\t'r1,'d1('r2d,'r3)");
        break;
      case CH:
        Format(instr, "ch\t'r1,'d1('r2d,'r3)");
        break;
      case CL:
        Format(instr, "cl\t'r1,'d1('r2d,'r3)");
        break;
      case CLI:
        Format(instr, "cli\t'd1('r3),'i8");
        break;
      case TM:
        Format(instr, "tm\t'd1('r3),'i8");
        break;
      case BC:
        Format(instr, "bc\t'm1,'d1('r2d,'r3)");
        break;
      case BCT:
        Format(instr, "bct\t'r1,'d1('r2d,'r3)");
        break;
      case ST:
        Format(instr, "st\t'r1,'d1('r2d,'r3)");
        break;
      case STC:
        Format(instr, "stc\t'r1,'d1('r2d,'r3)");
        break;
      case IC_z:
        Format(instr, "ic\t'r1,'d1('r2d,'r3)");
        break;
      case LD:
        Format(instr, "ld\t'f1,'d1('r2d,'r3)");
        break;
      case LE:
        Format(instr, "le\t'f1,'d1('r2d,'r3)");
        break;
      case LDGR:
        Format(instr, "ldgr\t'f5,'r6");
        break;
      case MS:
        Format(instr, "ms\t'r1,'d1('r2d,'r3)");
        break;
      case STE:
        Format(instr, "ste\t'f1,'d1('r2d,'r3)");
        break;
      case STD:
        Format(instr, "std\t'f1,'d1('r2d,'r3)");
        break;
      case CFDBR:
        Format(instr, "cfdbr\t'r5,'m2,'f6");
        break;
      case CDFBR:
        Format(instr, "cdfbr\t'f5,'m2,'r6");
        break;
      case CFEBR:
        Format(instr, "cfebr\t'r5,'m2,'f6");
        break;
      case CEFBR:
        Format(instr, "cefbr\t'f5,'m2,'r6");
        break;
      case CELFBR:
        Format(instr, "celfbr\t'f5,'m2,'r6");
        break;
      case CGEBR:
        Format(instr, "cgebr\t'r5,'m2,'f6");
        break;
      case CGDBR:
        Format(instr, "cgdbr\t'r5,'m2,'f6");
        break;
      case CEGBR:
        Format(instr, "cegbr\t'f5,'m2,'r6");
        break;
      case CDGBR:
        Format(instr, "cdgbr\t'f5,'m2,'r6");
        break;
      case CDLFBR:
        Format(instr, "cdlfbr\t'f5,'m2,'r6");
        break;
      case CDLGBR:
        Format(instr, "cdlgbr\t'f5,'m2,'r6");
        break;
      case CELGBR:
        Format(instr, "celgbr\t'f5,'m2,'r6");
        break;
      case CLFDBR:
        Format(instr, "clfdbr\t'r5,'m2,'f6");
        break;
      case CLFEBR:
        Format(instr, "clfebr\t'r5,'m2,'f6");
        break;
      case CLGEBR:
        Format(instr, "clgebr\t'r5,'m2,'f6");
        break;
      case CLGDBR:
        Format(instr, "clgdbr\t'r5,'m2,'f6");
        break;
      case AEBR:
        Format(instr, "aebr\t'f5,'f6");
        break;
      case SEBR:
        Format(instr, "sebr\t'f5,'f6");
        break;
      case MEEBR:
        Format(instr, "meebr\t'f5,'f6");
        break;
      case DEBR:
        Format(instr, "debr\t'f5,'f6");
        break;
      case ADBR:
        Format(instr, "adbr\t'f5,'f6");
        break;
      case SDBR:
        Format(instr, "sdbr\t'f5,'f6");
        break;
      case MDBR:
        Format(instr, "mdbr\t'f5,'f6");
        break;
      case DDBR:
        Format(instr, "ddbr\t'f5,'f6");
        break;
      case CDBR:
        Format(instr, "cdbr\t'f5,'f6");
        break;
      case CEBR:
        Format(instr, "cebr\t'f5,'f6");
        break;
      case SQDBR:
        Format(instr, "sqdbr\t'f5,'f6");
        break;
      case SQEBR:
        Format(instr, "sqebr\t'f5,'f6");
        break;
      case LCDBR:
        Format(instr, "lcdbr\t'f5,'f6");
        break;
      case LCEBR:
        Format(instr, "lcebr\t'f5,'f6");
        break;
      case STH:
        Format(instr, "sth\t'r1,'d1('r2d,'r3)");
        break;
      case SRDA:
        Format(instr, "srda\t'r1,'d1('r3)");
        break;
      case SRDL:
        Format(instr, "srdl\t'r1,'d1('r3)");
        break;
      case MADBR:
        Format(instr, "madbr\t'f3,'f5,'f6");
        break;
      case MSDBR:
        Format(instr, "msdbr\t'f3,'f5,'f6");
        break;
      case FLOGR:
        Format(instr, "flogr\t'r5,'r6");
        break;
      case FIEBRA:
        Format(instr, "fiebra\t'f5,'m2,'f6,'m3");
        break;
      case FIDBRA:
        Format(instr, "fidbra\t'f5,'m2,'f6,'m3");
        break;
      // TRAP4 is used in calling to native function. it will not be generated
      // in native code.
      case TRAP4: {
        Format(instr, "trap4");
        break;
      }
      case LPGR:
        Format(instr, "lpgr\t'r1, 'r2");
        break;
      case LPGFR:
        Format(instr, "lpgfr\t'r1,'r2");
        break;
      default:
        return false;
    }
    return true;
  }
  
  // Disassembles Six Byte S390 Instructions
  // @return true if successfully decoded
  bool Decoder::DecodeSixByte(Instruction* instr) {
    // Print the Instruction bits.
    out_buffer_pos_ +=
        SNPrintF(out_buffer_ + out_buffer_pos_, "%012" PRIx64 "   ",
                 instr->InstructionBits<SixByteInstr>());
  
    Opcode opcode = instr->S390OpcodeValue();
    switch (opcode) {
      case DUMY:
        Format(instr, "dumy\t'r1, 'd2 ( 'r2d, 'r3 )");
        break;
  #define DECODE_VRR_C_INSTRUCTIONS(name, opcode_name, opcode_value) \
    case opcode_name:                                                \
      Format(instr, #name "\t'f1,'f2,'f3");                          \
      break;
        S390_VRR_C_OPCODE_LIST(DECODE_VRR_C_INSTRUCTIONS)
  #undef DECODE_VRR_C_INSTRUCTIONS
      case LLILF:
        Format(instr, "llilf\t'r1,'i7");
        break;
      case LLIHF:
        Format(instr, "llihf\t'r1,'i7");
        break;
      case AFI:
        Format(instr, "afi\t'r1,'i7");
        break;
      case AIH:
        Format(instr, "aih\t'r1,'i7");
        break;
      case ASI:
        Format(instr, "asi\t'd2('r3),'ic");
        break;
      case AGSI:
        Format(instr, "agsi\t'd2('r3),'ic");
        break;
      case ALFI:
        Format(instr, "alfi\t'r1,'i7");
        break;
      case AHIK:
        Format(instr, "ahik\t'r1,'r2,'i1");
        break;
      case AGHIK:
        Format(instr, "aghik\t'r1,'r2,'i1");
        break;
      case CLGFI:
        Format(instr, "clgfi\t'r1,'i7");
        break;
      case CLFI:
        Format(instr, "clfi\t'r1,'i7");
        break;
      case CLIH:
        Format(instr, "clih\t'r1,'i7");
        break;
      case CIH:
        Format(instr, "cih\t'r1,'i2");
        break;
      case CFI:
        Format(instr, "cfi\t'r1,'i2");
        break;
      case CGFI:
        Format(instr, "cgfi\t'r1,'i2");
        break;
      case BRASL:
        Format(instr, "brasl\t'r1,'ie");
        break;
      case BRCL:
        Format(instr, "brcl\t'm1,'i5");
        break;
      case IIHF:
        Format(instr, "iihf\t'r1,'i7");
        break;
      case LGFI:
        Format(instr, "lgfi\t'r1,'i7");
        break;
      case IILF:
        Format(instr, "iilf\t'r1,'i7");
        break;
      case XIHF:
        Format(instr, "xihf\t'r1,'i7");
        break;
      case XILF:
        Format(instr, "xilf\t'r1,'i7");
        break;
      case SLLK:
        Format(instr, "sllk\t'r1,'r2,'d2('r3)");
        break;
      case SLLG:
        Format(instr, "sllg\t'r1,'r2,'d2('r3)");
        break;
      case RLL:
        Format(instr, "rll\t'r1,'r2,'d2('r3)");
        break;
      case RLLG:
        Format(instr, "rllg\t'r1,'r2,'d2('r3)");
        break;
      case SRLK:
        Format(instr, "srlk\t'r1,'r2,'d2('r3)");
        break;
      case SRLG:
        Format(instr, "srlg\t'r1,'r2,'d2('r3)");
        break;
      case SLAK:
        Format(instr, "slak\t'r1,'r2,'d2('r3)");
        break;
      case SLAG:
        Format(instr, "slag\t'r1,'r2,'d2('r3)");
        break;
      case SRAK:
        Format(instr, "srak\t'r1,'r2,'d2('r3)");
        break;
      case SRAG:
        Format(instr, "srag\t'r1,'r2,'d2('r3)");
        break;
      case RISBG:
        Format(instr, "risbg\t'r1,'r2,'i9,'ia,'ib");
        break;
      case RISBGN:
        Format(instr, "risbgn\t'r1,'r2,'i9,'ia,'ib");
        break;
      case LOCG:
        Format(instr, "locg\t'm2,'r1,'d2('r3)");
        break;
      case LOC:
        Format(instr, "loc\t'm2,'r1,'d2('r3)");
        break;
      case LMY:
        Format(instr, "lmy\t'r1,'r2,'d2('r3)");
        break;
      case LMG:
        Format(instr, "lmg\t'r1,'r2,'d2('r3)");
        break;
      case STMY:
        Format(instr, "stmy\t'r1,'r2,'d2('r3)");
        break;
      case STMG:
        Format(instr, "stmg\t'r1,'r2,'d2('r3)");
        break;
      case LT:
        Format(instr, "lt\t'r1,'d2('r2d,'r3)");
        break;
      case LTG:
        Format(instr, "ltg\t'r1,'d2('r2d,'r3)");
        break;
      case ML:
        Format(instr, "ml\t'r1,'d2('r2d,'r3)");
        break;
      case AY:
        Format(instr, "ay\t'r1,'d2('r2d,'r3)");
        break;
      case SY:
        Format(instr, "sy\t'r1,'d2('r2d,'r3)");
        break;
      case NY:
        Format(instr, "ny\t'r1,'d2('r2d,'r3)");
        break;
      case OY:
        Format(instr, "oy\t'r1,'d2('r2d,'r3)");
        break;
      case XY:
        Format(instr, "xy\t'r1,'d2('r2d,'r3)");
        break;
      case CY:
        Format(instr, "cy\t'r1,'d2('r2d,'r3)");
        break;
      case AHY:
        Format(instr, "ahy\t'r1,'d2('r2d,'r3)");
        break;
      case SHY:
        Format(instr, "shy\t'r1,'d2('r2d,'r3)");
        break;
      case LGH:
        Format(instr, "lgh\t'r1,'d2('r2d,'r3)");
        break;
      case AG:
        Format(instr, "ag\t'r1,'d2('r2d,'r3)");
        break;
      case AGF:
        Format(instr, "agf\t'r1,'d2('r2d,'r3)");
        break;
      case SG:
        Format(instr, "sg\t'r1,'d2('r2d,'r3)");
        break;
      case NG:
        Format(instr, "ng\t'r1,'d2('r2d,'r3)");
        break;
      case OG:
        Format(instr, "og\t'r1,'d2('r2d,'r3)");
        break;
      case XG:
        Format(instr, "xg\t'r1,'d2('r2d,'r3)");
        break;
      case CG:
        Format(instr, "cg\t'r1,'d2('r2d,'r3)");
        break;
      case LB:
        Format(instr, "lb\t'r1,'d2('r2d,'r3)");
        break;
      case LRVH:
        Format(instr, "lrvh\t'r1,'d2('r2d,'r3)");
        break;
      case LRV:
        Format(instr, "lrv\t'r1,'d2('r2d,'r3)");
        break;
      case LRVG:
        Format(instr, "lrvg\t'r1,'d2('r2d,'r3)");
        break;
      case LG:
        Format(instr, "lg\t'r1,'d2('r2d,'r3)");
        break;
      case LGF:
        Format(instr, "lgf\t'r1,'d2('r2d,'r3)");
        break;
      case LLGF:
        Format(instr, "llgf\t'r1,'d2('r2d,'r3)");
        break;
      case LY:
        Format(instr, "ly\t'r1,'d2('r2d,'r3)");
        break;
      case ALY:
        Format(instr, "aly\t'r1,'d2('r2d,'r3)");
        break;
      case ALG:
        Format(instr, "alg\t'r1,'d2('r2d,'r3)");
        break;
      case SLG:
        Format(instr, "slg\t'r1,'d2('r2d,'r3)");
        break;
      case SGF:
        Format(instr, "sgf\t'r1,'d2('r2d,'r3)");
        break;
      case SLY:
        Format(instr, "sly\t'r1,'d2('r2d,'r3)");
        break;
      case LLH:
        Format(instr, "llh\t'r1,'d2('r2d,'r3)");
        break;
      case LLGH:
        Format(instr, "llgh\t'r1,'d2('r2d,'r3)");
        break;
      case LLC:
        Format(instr, "llc\t'r1,'d2('r2d,'r3)");
        break;
      case LLGC:
        Format(instr, "llgc\t'r1,'d2('r2d,'r3)");
        break;
      case LDEB:
        Format(instr, "ldeb\t'f1,'d2('r2d,'r3)");
        break;
      case LAY:
        Format(instr, "lay\t'r1,'d2('r2d,'r3)");
        break;
      case LARL:
        Format(instr, "larl\t'r1,'i5");
        break;
      case LGB:
        Format(instr, "lgb\t'r1,'d2('r2d,'r3)");
        break;
      case CHY:
        Format(instr, "chy\t'r1,'d2('r2d,'r3)");
        break;
      case CLY:
        Format(instr, "cly\t'r1,'d2('r2d,'r3)");
        break;
      case CLIY:
        Format(instr, "cliy\t'd2('r3),'i8");
        break;
      case TMY:
        Format(instr, "tmy\t'd2('r3),'i8");
        break;
      case CLG:
        Format(instr, "clg\t'r1,'d2('r2d,'r3)");
        break;
      case BCTG:
        Format(instr, "bctg\t'r1,'d2('r2d,'r3)");
        break;
      case STY:
        Format(instr, "sty\t'r1,'d2('r2d,'r3)");
        break;
      case STRVH:
        Format(instr, "strvh\t'r1,'d2('r2d,'r3)");
        break;
      case STRV:
        Format(instr, "strv\t'r1,'d2('r2d,'r3)");
        break;
      case STRVG:
        Format(instr, "strvg\t'r1,'d2('r2d,'r3)");
        break;
      case STG:
        Format(instr, "stg\t'r1,'d2('r2d,'r3)");
        break;
      case ICY:
        Format(instr, "icy\t'r1,'d2('r2d,'r3)");
        break;
      case MVC:
        Format(instr, "mvc\t'd3('i8,'r3),'d4('r7)");
        break;
      case MVHI:
        Format(instr, "mvhi\t'd3('r3),'id");
        break;
      case MVGHI:
        Format(instr, "mvghi\t'd3('r3),'id");
        break;
      case ALGFI:
        Format(instr, "algfi\t'r1,'i7");
        break;
      case SLGFI:
        Format(instr, "slgfi\t'r1,'i7");
        break;
      case SLFI:
        Format(instr, "slfi\t'r1,'i7");
        break;
      case NIHF:
        Format(instr, "nihf\t'r1,'i7");
        break;
      case NILF:
        Format(instr, "nilf\t'r1,'i7");
        break;
      case OIHF:
        Format(instr, "oihf\t'r1,'i7");
        break;
      case OILF:
        Format(instr, "oilf\t'r1,'i7");
        break;
      case MSFI:
        Format(instr, "msfi\t'r1,'i7");
        break;
      case MSGFI:
        Format(instr, "msgfi\t'r1,'i7");
        break;
      case LDY:
        Format(instr, "ldy\t'f1,'d2('r2d,'r3)");
        break;
      case LEY:
        Format(instr, "ley\t'f1,'d2('r2d,'r3)");
        break;
      case MSG:
        Format(instr, "msg\t'r1,'d2('r2d,'r3)");
        break;
      case DSG:
        Format(instr, "dsg\t'r1,'d2('r2d,'r3)");
        break;
      case DSGF:
        Format(instr, "dsgf\t'r1,'d2('r2d,'r3)");
        break;
      case MSGF:
        Format(instr, "msgf\t'r1,'d2('r2d,'r3)");
        break;
      case MSY:
        Format(instr, "msy\t'r1,'d2('r2d,'r3)");
        break;
      case STEY:
        Format(instr, "stey\t'f1,'d2('r2d,'r3)");
        break;
      case STDY:
        Format(instr, "stdy\t'f1,'d2('r2d,'r3)");
        break;
      case ADB:
        Format(instr, "adb\t'f1,'d1('r2d, 'r3)");
        break;
      case AEB:
        Format(instr, "aeb\t'f1,'d1('r2d, 'r3)");
        break;
      case CDB:
        Format(instr, "cdb\t'f1,'d1('r2d, 'r3)");
        break;
      case CEB:
        Format(instr, "ceb\t'f1,'d1('r2d, 'r3)");
        break;
      case SDB:
        Format(instr, "sdb\t'r1,'d1('r2d, 'r3)");
        break;
      case SEB:
        Format(instr, "seb\t'r1,'d1('r2d, 'r3)");
        break;
      case MDB:
        Format(instr, "mdb\t'r1,'d1('r2d, 'r3)");
        break;
      case MEEB:
        Format(instr, "meeb\t'r1,'d1('r2d, 'r3)");
        break;
      case DDB:
        Format(instr, "ddb\t'r1,'d1('r2d, 'r3)");
        break;
      case DEB:
        Format(instr, "deb\t'r1,'d1('r2d, 'r3)");
        break;
      case SQDB:
        Format(instr, "sqdb\t'r1,'d1('r2d, 'r3)");
        break;
      case PFD:
        Format(instr, "pfd\t'm1,'d2('r2d,'r3)");
        break;
      default:
        return false;
    }
    return true;
  }
  
  #undef VERIFIY
  
  // Disassemble the instruction at *instr_ptr into the output buffer.
  int Decoder::InstructionDecode(byte* instr_ptr) {
    Instruction* instr = Instruction::At(instr_ptr);
    int instrLength = instr->InstructionLength();
  
    if (2 == instrLength)
      DecodeTwoByte(instr);
    else if (4 == instrLength)
      DecodeFourByte(instr);
    else
      DecodeSixByte(instr);
  
    return instrLength;
  }
  
  }  // namespace internal
  }  // namespace v8
  
  //------------------------------------------------------------------------------
  
  namespace disasm {
  
  const char* NameConverter::NameOfAddress(byte* addr) const {
    v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
    return tmp_buffer_.start();
  }
  
  const char* NameConverter::NameOfConstant(byte* addr) const {
    return NameOfAddress(addr);
  }
  
  const char* NameConverter::NameOfCPURegister(int reg) const {
    return v8::internal::GetRegConfig()->GetGeneralRegisterName(reg);
  }
  
  const char* NameConverter::NameOfByteCPURegister(int reg) const {
    UNREACHABLE();  // S390 does not have the concept of a byte register
    return "nobytereg";
  }
  
  const char* NameConverter::NameOfXMMRegister(int reg) const {
    // S390 does not have XMM register
    // TODO(joransiu): Consider update this for Vector Regs
    UNREACHABLE();
    return "noxmmreg";
  }
  
  const char* NameConverter::NameInCode(byte* addr) const {
    // The default name converter is called for unknown code. So we will not try
    // to access any memory.
    return "";
  }
  
  //------------------------------------------------------------------------------
  
  Disassembler::Disassembler(const NameConverter& converter)
      : converter_(converter) {}
  
  Disassembler::~Disassembler() {}
  
  int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
                                      byte* instruction) {
    v8::internal::Decoder d(converter_, buffer);
    return d.InstructionDecode(instruction);
  }
  
  // The S390 assembler does not currently use constant pools.
  int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
  
  void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
    NameConverter converter;
    Disassembler d(converter);
    for (byte* pc = begin; pc < end;) {
      v8::internal::EmbeddedVector<char, 128> buffer;
      buffer[0] = '\0';
      byte* prev_pc = pc;
      pc += d.InstructionDecode(buffer, pc);
      v8::internal::PrintF(f, "%p    %08x      %s\n", static_cast<void*>(prev_pc),
                           *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
    }
  }
  
  }  // namespace disasm
  
  #endif  // V8_TARGET_ARCH_S390
  