Error X86RACFGBuilder::moveRegToStackArg()

in erts/emulator/asmjit/x86/x86rapass.cpp [792:992]


Error X86RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept {
  DebugUtils::unused(invokeNode);
  ASMJIT_ASSERT(arg.isStack());

  Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset());
  Reg r0, r1;

  VirtReg* vr = cc()->virtRegById(reg.id());
  uint32_t registerSize = cc()->registerSize();
  uint32_t instId = 0;

  uint32_t dstTypeId = arg.typeId();
  uint32_t srcTypeId = vr->typeId();

  switch (dstTypeId) {
    case Type::kIdI64:
    case Type::kIdU64:
      // Extend BYTE->QWORD (GP).
      if (Type::isGp8(srcTypeId)) {
        r1.setRegT<Reg::kTypeGpbLo>(reg.id());

        instId = (dstTypeId == Type::kIdI64 && srcTypeId == Type::kIdI8) ? Inst::kIdMovsx : Inst::kIdMovzx;
        goto ExtendMovGpXQ;
      }

      // Extend WORD->QWORD (GP).
      if (Type::isGp16(srcTypeId)) {
        r1.setRegT<Reg::kTypeGpw>(reg.id());

        instId = (dstTypeId == Type::kIdI64 && srcTypeId == Type::kIdI16) ? Inst::kIdMovsx : Inst::kIdMovzx;
        goto ExtendMovGpXQ;
      }

      // Extend DWORD->QWORD (GP).
      if (Type::isGp32(srcTypeId)) {
        r1.setRegT<Reg::kTypeGpd>(reg.id());

        instId = Inst::kIdMovsxd;
        if (dstTypeId == Type::kIdI64 && srcTypeId == Type::kIdI32)
          goto ExtendMovGpXQ;
        else
          goto ZeroExtendGpDQ;
      }

      // Move QWORD (GP).
      if (Type::isGp64(srcTypeId)) goto MovGpQ;
      if (Type::isMmx(srcTypeId)) goto MovMmQ;
      if (Type::isVec(srcTypeId)) goto MovXmmQ;
      break;

    case Type::kIdI32:
    case Type::kIdU32:
    case Type::kIdI16:
    case Type::kIdU16:
      // DWORD <- WORD (Zero|Sign Extend).
      if (Type::isGp16(srcTypeId)) {
        bool isDstSigned = dstTypeId == Type::kIdI16 || dstTypeId == Type::kIdI32;
        bool isSrcSigned = srcTypeId == Type::kIdI8  || srcTypeId == Type::kIdI16;

        r1.setRegT<Reg::kTypeGpw>(reg.id());
        instId = isDstSigned && isSrcSigned ? Inst::kIdMovsx : Inst::kIdMovzx;
        goto ExtendMovGpD;
      }

      // DWORD <- BYTE (Zero|Sign Extend).
      if (Type::isGp8(srcTypeId)) {
        bool isDstSigned = dstTypeId == Type::kIdI16 || dstTypeId == Type::kIdI32;
        bool isSrcSigned = srcTypeId == Type::kIdI8  || srcTypeId == Type::kIdI16;

        r1.setRegT<Reg::kTypeGpbLo>(reg.id());
        instId = isDstSigned && isSrcSigned ? Inst::kIdMovsx : Inst::kIdMovzx;
        goto ExtendMovGpD;
      }
      ASMJIT_FALLTHROUGH;

    case Type::kIdI8:
    case Type::kIdU8:
      if (Type::isInt(srcTypeId)) goto MovGpD;
      if (Type::isMmx(srcTypeId)) goto MovMmD;
      if (Type::isVec(srcTypeId)) goto MovXmmD;
      break;

    case Type::kIdMmx32:
    case Type::kIdMmx64:
      // Extend BYTE->QWORD (GP).
      if (Type::isGp8(srcTypeId)) {
        r1.setRegT<Reg::kTypeGpbLo>(reg.id());

        instId = Inst::kIdMovzx;
        goto ExtendMovGpXQ;
      }

      // Extend WORD->QWORD (GP).
      if (Type::isGp16(srcTypeId)) {
        r1.setRegT<Reg::kTypeGpw>(reg.id());

        instId = Inst::kIdMovzx;
        goto ExtendMovGpXQ;
      }

      if (Type::isGp32(srcTypeId)) goto ExtendMovGpDQ;
      if (Type::isGp64(srcTypeId)) goto MovGpQ;
      if (Type::isMmx(srcTypeId)) goto MovMmQ;
      if (Type::isVec(srcTypeId)) goto MovXmmQ;
      break;

    case Type::kIdF32:
    case Type::kIdF32x1:
      if (Type::isVec(srcTypeId)) goto MovXmmD;
      break;

    case Type::kIdF64:
    case Type::kIdF64x1:
      if (Type::isVec(srcTypeId)) goto MovXmmQ;
      break;

    default:
      if (Type::isVec(dstTypeId) && reg.as<Reg>().isVec()) {
        stackPtr.setSize(Type::sizeOf(dstTypeId));
        uint32_t vMovInstId = choose(Inst::kIdMovaps, Inst::kIdVmovaps);

        if (Type::isVec128(dstTypeId))
          r0.setRegT<Reg::kTypeXmm>(reg.id());
        else if (Type::isVec256(dstTypeId))
          r0.setRegT<Reg::kTypeYmm>(reg.id());
        else if (Type::isVec512(dstTypeId))
          r0.setRegT<Reg::kTypeZmm>(reg.id());
        else
          break;

        return cc()->emit(vMovInstId, stackPtr, r0);
      }
      break;
  }
  return DebugUtils::errored(kErrorInvalidAssignment);

  // Extend+Move Gp.
ExtendMovGpD:
  stackPtr.setSize(4);
  r0.setRegT<Reg::kTypeGpd>(reg.id());

  ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1));
  ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0));
  return kErrorOk;

ExtendMovGpXQ:
  if (registerSize == 8) {
    stackPtr.setSize(8);
    r0.setRegT<Reg::kTypeGpq>(reg.id());

    ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1));
    ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0));
  }
  else {
    stackPtr.setSize(4);
    r0.setRegT<Reg::kTypeGpd>(reg.id());

    ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1));

ExtendMovGpDQ:
    ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0));
    stackPtr.addOffsetLo32(4);
    ASMJIT_PROPAGATE(cc()->emit(Inst::kIdAnd, stackPtr, 0));
  }
  return kErrorOk;

ZeroExtendGpDQ:
  stackPtr.setSize(4);
  r0.setRegT<Reg::kTypeGpd>(reg.id());
  goto ExtendMovGpDQ;

MovGpD:
  stackPtr.setSize(4);
  r0.setRegT<Reg::kTypeGpd>(reg.id());
  return cc()->emit(Inst::kIdMov, stackPtr, r0);

MovGpQ:
  stackPtr.setSize(8);
  r0.setRegT<Reg::kTypeGpq>(reg.id());
  return cc()->emit(Inst::kIdMov, stackPtr, r0);

MovMmD:
  stackPtr.setSize(4);
  r0.setRegT<Reg::kTypeMm>(reg.id());
  return cc()->emit(choose(Inst::kIdMovd, Inst::kIdVmovd), stackPtr, r0);

MovMmQ:
  stackPtr.setSize(8);
  r0.setRegT<Reg::kTypeMm>(reg.id());
  return cc()->emit(choose(Inst::kIdMovq, Inst::kIdVmovq), stackPtr, r0);

MovXmmD:
  stackPtr.setSize(4);
  r0.setRegT<Reg::kTypeXmm>(reg.id());
  return cc()->emit(choose(Inst::kIdMovss, Inst::kIdVmovss), stackPtr, r0);

MovXmmQ:
  stackPtr.setSize(8);
  r0.setRegT<Reg::kTypeXmm>(reg.id());
  return cc()->emit(choose(Inst::kIdMovlps, Inst::kIdVmovlps), stackPtr, r0);
}