void Simulator::DecodeType7()

in runtime/vm/simulator_arm.cc [2488:2884]


void Simulator::DecodeType7(Instr* instr) {
  if (instr->Bit(24) == 1) {
    // Format(instr, "svc #'svc");
    SupervisorCall(instr);
  } else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
    if (instr->Bit(4) == 0) {
      // VFP Data Processing
      SRegister sd;
      SRegister sn;
      SRegister sm;
      DRegister dd;
      DRegister dn;
      DRegister dm;
      if (instr->Bit(8) == 0) {
        sd = instr->SdField();
        sn = instr->SnField();
        sm = instr->SmField();
        dd = kNoDRegister;
        dn = kNoDRegister;
        dm = kNoDRegister;
      } else {
        sd = kNoSRegister;
        sn = kNoSRegister;
        sm = kNoSRegister;
        dd = instr->DdField();
        dn = instr->DnField();
        dm = instr->DmField();
      }
      switch (instr->Bits(20, 4) & 0xb) {
        case 1:  // vnmla, vnmls, vnmul
        default: {
          UnimplementedInstruction(instr);
          break;
        }
        case 0: {  // vmla, vmls floating-point
          if (instr->Bit(8) == 0) {
            float addend = get_sregister(sn) * get_sregister(sm);
            float sd_val = get_sregister(sd);
            if (instr->Bit(6) == 0) {
              // Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
            } else {
              // Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
              addend = -addend;
            }
            set_sregister(sd, sd_val + addend);
          } else {
            double addend = get_dregister(dn) * get_dregister(dm);
            double dd_val = get_dregister(dd);
            if (instr->Bit(6) == 0) {
              // Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
            } else {
              // Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
              addend = -addend;
            }
            set_dregister(dd, dd_val + addend);
          }
          break;
        }
        case 2: {  // vmul
          if (instr->Bit(8) == 0) {
            // Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
            set_sregister(sd, get_sregister(sn) * get_sregister(sm));
          } else {
            // Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
            set_dregister(dd, get_dregister(dn) * get_dregister(dm));
          }
          break;
        }
        case 8: {  // vdiv
          if (instr->Bit(8) == 0) {
            // Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
            set_sregister(sd, get_sregister(sn) / get_sregister(sm));
          } else {
            // Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
            set_dregister(dd, get_dregister(dn) / get_dregister(dm));
          }
          break;
        }
        case 3: {  // vadd, vsub floating-point
          if (instr->Bit(8) == 0) {
            if (instr->Bit(6) == 0) {
              // Format(instr, "vadds'cond 'sd, 'sn, 'sm");
              set_sregister(sd, get_sregister(sn) + get_sregister(sm));
            } else {
              // Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
              set_sregister(sd, get_sregister(sn) - get_sregister(sm));
            }
          } else {
            if (instr->Bit(6) == 0) {
              // Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
              set_dregister(dd, get_dregister(dn) + get_dregister(dm));
            } else {
              // Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
              set_dregister(dd, get_dregister(dn) - get_dregister(dm));
            }
          }
          break;
        }
        case 0xb: {                  // Other VFP data-processing instructions
          if (instr->Bit(6) == 0) {  // vmov immediate
            if (instr->Bit(8) == 0) {
              // Format(instr, "vmovs'cond 'sd, #'immf");
              set_sregister(sd, instr->ImmFloatField());
            } else {
              // Format(instr, "vmovd'cond 'dd, #'immd");
              set_dregister(dd, instr->ImmDoubleField());
            }
            break;
          }
          switch (instr->Bits(16, 4)) {
            case 0: {  // vmov immediate, vmov register, vabs
              switch (instr->Bits(6, 2)) {
                case 1: {  // vmov register
                  if (instr->Bit(8) == 0) {
                    // Format(instr, "vmovs'cond 'sd, 'sm");
                    set_sregister(sd, get_sregister(sm));
                  } else {
                    // Format(instr, "vmovd'cond 'dd, 'dm");
                    set_dregister(dd, get_dregister(dm));
                  }
                  break;
                }
                case 3: {  // vabs
                  if (instr->Bit(8) == 0) {
                    // Format(instr, "vabss'cond 'sd, 'sm");
                    set_sregister(sd, fabsf(get_sregister(sm)));
                  } else {
                    // Format(instr, "vabsd'cond 'dd, 'dm");
                    set_dregister(dd, fabs(get_dregister(dm)));
                  }
                  break;
                }
                default: {
                  UnimplementedInstruction(instr);
                  break;
                }
              }
              break;
            }
            case 1: {  // vneg, vsqrt
              switch (instr->Bits(6, 2)) {
                case 1: {  // vneg
                  if (instr->Bit(8) == 0) {
                    // Format(instr, "vnegs'cond 'sd, 'sm");
                    set_sregister(sd, -get_sregister(sm));
                  } else {
                    // Format(instr, "vnegd'cond 'dd, 'dm");
                    set_dregister(dd, -get_dregister(dm));
                  }
                  break;
                }
                case 3: {  // vsqrt
                  if (instr->Bit(8) == 0) {
                    // Format(instr, "vsqrts'cond 'sd, 'sm");
                    set_sregister(sd, sqrtf(get_sregister(sm)));
                  } else {
                    // Format(instr, "vsqrtd'cond 'dd, 'dm");
                    set_dregister(dd, sqrt(get_dregister(dm)));
                  }
                  break;
                }
                default: {
                  UnimplementedInstruction(instr);
                  break;
                }
              }
              break;
            }
            case 4:                      // vcmp, vcmpe
            case 5: {                    // vcmp #0.0, vcmpe #0.0
              if (instr->Bit(7) == 1) {  // vcmpe
                UnimplementedInstruction(instr);
              } else {
                fp_n_flag_ = false;
                fp_z_flag_ = false;
                fp_c_flag_ = false;
                fp_v_flag_ = false;
                if (instr->Bit(8) == 0) {  // vcmps
                  float sd_val = get_sregister(sd);
                  float sm_val;
                  if (instr->Bit(16) == 0) {
                    // Format(instr, "vcmps'cond 'sd, 'sm");
                    sm_val = get_sregister(sm);
                  } else {
                    // Format(instr, "vcmps'cond 'sd, #0.0");
                    sm_val = 0.0f;
                  }
                  if (isnan(sd_val) || isnan(sm_val)) {
                    fp_c_flag_ = true;
                    fp_v_flag_ = true;
                  } else if (sd_val == sm_val) {
                    fp_z_flag_ = true;
                    fp_c_flag_ = true;
                  } else if (sd_val < sm_val) {
                    fp_n_flag_ = true;
                  } else {
                    fp_c_flag_ = true;
                  }
                } else {  // vcmpd
                  double dd_val = get_dregister(dd);
                  double dm_val;
                  if (instr->Bit(16) == 0) {
                    // Format(instr, "vcmpd'cond 'dd, 'dm");
                    dm_val = get_dregister(dm);
                  } else {
                    // Format(instr, "vcmpd'cond 'dd, #0.0");
                    dm_val = 0.0;
                  }
                  if (isnan(dd_val) || isnan(dm_val)) {
                    fp_c_flag_ = true;
                    fp_v_flag_ = true;
                  } else if (dd_val == dm_val) {
                    fp_z_flag_ = true;
                    fp_c_flag_ = true;
                  } else if (dd_val < dm_val) {
                    fp_n_flag_ = true;
                  } else {
                    fp_c_flag_ = true;
                  }
                }
              }
              break;
            }
            case 7: {  // vcvt between double-precision and single-precision
              if (instr->Bit(8) == 0) {
                // Format(instr, "vcvtds'cond 'dd, 'sm");
                dd = instr->DdField();
                set_dregister(dd, static_cast<double>(get_sregister(sm)));
              } else {
                // Format(instr, "vcvtsd'cond 'sd, 'dm");
                sd = instr->SdField();
                set_sregister(sd, static_cast<float>(get_dregister(dm)));
              }
              break;
            }
            case 8: {  // vcvt, vcvtr between floating-point and integer
              sm = instr->SmField();
              int32_t sm_int = get_sregister_bits(sm);
              uint32_t ud_val = 0;
              int32_t id_val = 0;
              if (instr->Bit(7) == 0) {  // vcvtsu, vcvtdu
                ud_val = static_cast<uint32_t>(sm_int);
              } else {  // vcvtsi, vcvtdi
                id_val = sm_int;
              }
              if (instr->Bit(8) == 0) {
                float sd_val;
                if (instr->Bit(7) == 0) {
                  // Format(instr, "vcvtsu'cond 'sd, 'sm");
                  sd_val = static_cast<float>(ud_val);
                } else {
                  // Format(instr, "vcvtsi'cond 'sd, 'sm");
                  sd_val = static_cast<float>(id_val);
                }
                set_sregister(sd, sd_val);
              } else {
                double dd_val;
                if (instr->Bit(7) == 0) {
                  // Format(instr, "vcvtdu'cond 'dd, 'sm");
                  dd_val = static_cast<double>(ud_val);
                } else {
                  // Format(instr, "vcvtdi'cond 'dd, 'sm");
                  dd_val = static_cast<double>(id_val);
                }
                set_dregister(dd, dd_val);
              }
              break;
            }
            case 12:
            case 13: {  // vcvt, vcvtr between floating-point and integer
              // We do not need to record exceptions in the FPSCR cumulative
              // flags, because we do not use them.
              if (instr->Bit(7) == 0) {
                // We only support round-to-zero mode
                UnimplementedInstruction(instr);
                break;
              }
              int32_t id_val = 0;
              uint32_t ud_val = 0;
              if (instr->Bit(8) == 0) {
                float sm_val = get_sregister(sm);
                if (instr->Bit(16) == 0) {
                  // Format(instr, "vcvtus'cond 'sd, 'sm");
                  if (sm_val >= static_cast<float>(INT32_MAX)) {
                    ud_val = INT32_MAX;
                  } else if (sm_val > 0.0) {
                    ud_val = static_cast<uint32_t>(sm_val);
                  }
                } else {
                  // Format(instr, "vcvtis'cond 'sd, 'sm");
                  if (sm_val <= static_cast<float>(INT32_MIN)) {
                    id_val = INT32_MIN;
                  } else if (sm_val >= static_cast<float>(INT32_MAX)) {
                    id_val = INT32_MAX;
                  } else {
                    id_val = static_cast<int32_t>(sm_val);
                  }
                  ASSERT((id_val >= 0) || !(sm_val >= 0.0));
                }
              } else {
                sd = instr->SdField();
                double dm_val = get_dregister(dm);
                if (instr->Bit(16) == 0) {
                  // Format(instr, "vcvtud'cond 'sd, 'dm");
                  if (dm_val >= static_cast<double>(INT32_MAX)) {
                    ud_val = INT32_MAX;
                  } else if (dm_val > 0.0) {
                    ud_val = static_cast<uint32_t>(dm_val);
                  }
                } else {
                  // Format(instr, "vcvtid'cond 'sd, 'dm");
                  if (dm_val <= static_cast<double>(INT32_MIN)) {
                    id_val = INT32_MIN;
                  } else if (dm_val >= static_cast<double>(INT32_MAX)) {
                    id_val = INT32_MAX;
                  } else if (isnan(dm_val)) {
                    id_val = 0;
                  } else {
                    id_val = static_cast<int32_t>(dm_val);
                  }
                  ASSERT((id_val >= 0) || !(dm_val >= 0.0));
                }
              }
              int32_t sd_val;
              if (instr->Bit(16) == 0) {
                sd_val = static_cast<int32_t>(ud_val);
              } else {
                sd_val = id_val;
              }
              set_sregister_bits(sd, sd_val);
              break;
            }
            case 2:   // vcvtb, vcvtt
            case 3:   // vcvtb, vcvtt
            case 9:   // undefined
            case 10:  // vcvt between floating-point and fixed-point
            case 11:  // vcvt between floating-point and fixed-point
            case 14:  // vcvt between floating-point and fixed-point
            case 15:  // vcvt between floating-point and fixed-point
            default: {
              UnimplementedInstruction(instr);
              break;
            }
          }
        } break;
      }
    } else {
      // 8, 16, or 32-bit Transfer between ARM Core and VFP
      if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
        Register rd = instr->RdField();
        SRegister sn = instr->SnField();
        if (instr->Bit(20) == 0) {
          // Format(instr, "vmovs'cond 'sn, 'rd");
          set_sregister_bits(sn, get_register(rd));
        } else {
          // Format(instr, "vmovr'cond 'rd, 'sn");
          set_register(rd, get_sregister_bits(sn));
        }
      } else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) &&
                 (instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) {
        DRegister dn = instr->DnField();
        Register rd = instr->RdField();
        const int32_t src_value = get_register(rd);
        const int64_t dst_value = get_dregister_bits(dn);
        int32_t dst_lo = Utils::Low32Bits(dst_value);
        int32_t dst_hi = Utils::High32Bits(dst_value);
        if (instr->Bit(21) == 0) {
          // Format(instr, "vmovd'cond 'dn[0], 'rd");
          dst_lo = src_value;
        } else {
          // Format(instr, "vmovd'cond 'dn[1], 'rd");
          dst_hi = src_value;
        }
        set_dregister_bits(dn, Utils::LowHighTo64Bits(dst_lo, dst_hi));
      } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) {
        if (instr->Bits(12, 4) == 0xf) {
          // Format(instr, "vmrs'cond APSR, FPSCR");
          n_flag_ = fp_n_flag_;
          z_flag_ = fp_z_flag_;
          c_flag_ = fp_c_flag_;
          v_flag_ = fp_v_flag_;
        } else {
          // Format(instr, "vmrs'cond 'rd, FPSCR");
          const int32_t n_flag = fp_n_flag_ ? (1 << 31) : 0;
          const int32_t z_flag = fp_z_flag_ ? (1 << 30) : 0;
          const int32_t c_flag = fp_c_flag_ ? (1 << 29) : 0;
          const int32_t v_flag = fp_v_flag_ ? (1 << 28) : 0;
          set_register(instr->RdField(), n_flag | z_flag | c_flag | v_flag);
        }
      } else {
        UnimplementedInstruction(instr);
      }
    }
  } else {
    UnimplementedInstruction(instr);
  }
}