bool X86MachineInstructionRaiser::raiseMoveToMemInstr()

in X86/X86MachineInstructionRaiser.cpp [2211:2486]


bool X86MachineInstructionRaiser::raiseMoveToMemInstr(const MachineInstr &MI,
                                                      Value *MemRefVal) {
  unsigned int SrcOpIndex = getMemoryRefOpIndex(MI) + X86::AddrNumOperands;

  // If the source operand is neither an immediate or a register, check for an
  // implicit register use
  if (!MI.getOperand(SrcOpIndex).isImm() && !MI.getOperand(SrcOpIndex).isReg()) {
    MCInstrDesc Desc = MI.getDesc();
    assert(Desc.getNumImplicitUses() == 1 && "Expected one implicit use");
    for (unsigned int i = SrcOpIndex + 1; i < MI.getNumOperands(); ++i) {
      if (MI.getOperand(i).isUse() && MI.getOperand(i).isReg()) {
        SrcOpIndex = i;
        break;
      }
    }
  }

  const MachineOperand &SrcOp = MI.getOperand(SrcOpIndex);

  // Is this a mov instruction?
  bool isMovInst = instrNameStartsWith(MI, "MOV");

  assert((SrcOp.isImm() || SrcOp.isReg()) &&
         "Register or immediate value source expected in a move to mem "
         "instruction");
  // Get the BasicBlock corresponding to MachineBasicBlock of MI.
  // Raised instruction is added to this BasicBlock.
  BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());

  Value *SrcValue = nullptr;
  Type *SrcOpTy = nullptr;

  // If Source op is immediate, create a constant int value
  // of type memory location.
  if (SrcOp.isImm()) {
    SrcOpTy = getImmOperandType(MI, SrcOpIndex);
    int64_t SrcImm = SrcOp.getImm();
    if (isMovInst) {
      if (SrcImm > 0) {
        // Check if the immediate value corresponds to a global variable.
        Value *GV = getGlobalVariableValueAt(MI, SrcImm);
        if (GV != nullptr)
          SrcValue = GV;
        else {
          SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
        }
      } else
        SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
    } else
      SrcValue = ConstantInt::get(SrcOpTy, SrcImm);
  } else {
    // If it is not an immediate value, get source value
    SrcValue = getRegOperandValue(MI, SrcOpIndex);
    SrcOpTy = getPhysRegOperandType(MI, SrcOpIndex);
  }
  assert(SrcValue != nullptr &&
         "Unable to get source value while raising move to mem instruction");
  // Load the value from memory location of memRefValue.
  // memRefVal is either an AllocaInst (stack access) or GlobalValue (global
  // data access) or an effective address value.
  assert((isa<AllocaInst>(MemRefVal) || isEffectiveAddrValue(MemRefVal) ||
          isa<GlobalValue>(MemRefVal) || isa<GetElementPtrInst>(MemRefVal) ||
          MemRefVal->getType()->isPointerTy()) &&
         "Unexpected type of memory reference in mem-to-reg instruction");

  // If memory reference is not a pointer type, cast it to a pointer
  Type *DstMemTy = MemRefVal->getType();
  LLVMContext &Ctx(MF.getFunction().getContext());
  if (!DstMemTy->isPointerTy()) {
    // Cast it as pointer to SrcOpTy
    PointerType *PtrTy = nullptr;
    auto Opc = MI.getOpcode();
    auto MemSzInBits = getInstructionMemOpSize(Opc) * 8;
    if (isSSE2Instruction(Opc)) {
      PtrTy = getRaisedValues()->getSSEInstructionType(MI, Ctx)->getPointerTo();
    } else {
      assert(MemSzInBits > 0 && "Unexpected memory access size of instruction");
      PtrTy = Type::getIntNPtrTy(Ctx, MemSzInBits);
    }
    IntToPtrInst *convIntToPtr = new IntToPtrInst(MemRefVal, PtrTy);
    RaisedBB->getInstList().push_back(convIntToPtr);
    MemRefVal = convIntToPtr;
  }

  // This instruction moves a source value to memory. So, if the types of
  // the source value and that of the memory pointer element are not the
  // same as that of the store size of the instruction, cast them as needed.
  unsigned int memSzInBits = getInstructionMemOpSize(MI.getOpcode()) * 8;
  // Consider store value type to be the same as source value type, by default.
  Type *StoreTy = SrcValue->getType();
  if (SrcValue->getType()->isIntegerTy())
    StoreTy = Type::getIntNTy(Ctx, memSzInBits);
  else if (SrcValue->getType()->isFloatingPointTy()) {
    if (memSzInBits == 32)
      StoreTy = Type::getFloatTy(Ctx);
    else if (memSzInBits == 64)
      StoreTy = Type::getDoubleTy(Ctx);
  }

  bool SignExtend = MI.getOpcode() == X86::MOV64mi32;
  // Cast SrcValue and MemRefVal as needed.
  MemRefVal = getRaisedValues()->castValue(MemRefVal, StoreTy->getPointerTo(),
                                           RaisedBB);
  SrcValue = getRaisedValues()->castValue(SrcValue, StoreTy, RaisedBB, SignExtend);

  if (!isMovInst) {
    // If this is not an instruction that just moves SrcValue, load from memory,
    // generate the instruction that performs the appropriate operation.

    // Load the value from memory location
    auto align =
        MemRefVal->getPointerAlignment(MR->getModule()->getDataLayout());
    LoadInst *LdInst =
        new LoadInst(MemRefVal->getType()->getPointerElementType(), MemRefVal,
                     "", false, align, RaisedBB);
    assert((LdInst != nullptr) && "Memory value expected to be loaded while "
                                  "raising binary mem op instruction");
    assert((SrcValue != nullptr) && "Source value expected to be loaded while "
                                    "raising binary mem op instruction");

    std::set<unsigned> AffectedEFlags;

    Instruction *BinOpInst = nullptr;

    // Generate instruction to perform appropriate operation to produce the
    // value be stored.
    switch (MI.getOpcode()) {
    case X86::ADD8mi:
    case X86::ADD8mi8:
    case X86::ADD8mr:
    case X86::ADD16mi:
    case X86::ADD16mi8:
    case X86::ADD16mr:
    case X86::ADD32mi:
    case X86::ADD32mi8:
    case X86::ADD32mr:
    case X86::ADD64mi8:
    case X86::ADD64i32:
    case X86::ADD64mr:
    case X86::INC8m:
    case X86::INC16m:
    case X86::INC32m:
    case X86::INC64m: {
      // Generate Add instruction
      BinOpInst = BinaryOperator::CreateAdd(LdInst, SrcValue);

      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::AND8mi:
    case X86::AND8mi8:
    case X86::AND8mr:
    case X86::AND16mi:
    case X86::AND16mi8:
    case X86::AND16mr:
    case X86::AND32mi:
    case X86::AND32mi8:
    case X86::AND32mr:
    case X86::AND64mi8:
    case X86::AND64mi32:
    case X86::AND64mr: {
      BinOpInst = BinaryOperator::CreateAnd(LdInst, SrcValue);

      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::OR8mi:
    case X86::OR8mi8:
    case X86::OR8mr:
    case X86::OR16mi:
    case X86::OR16mi8:
    case X86::OR16mr:
    case X86::OR32mi:
    case X86::OR32mi8:
    case X86::OR32mr:
    case X86::OR64mi8:
    case X86::OR64mi32:
    case X86::OR64mr: {
      BinOpInst = BinaryOperator::CreateOr(LdInst, SrcValue);

      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::XOR8mi:
    case X86::XOR8mi8:
    case X86::XOR8mr:
    case X86::XOR16mi:
    case X86::XOR16mi8:
    case X86::XOR16mr:
    case X86::XOR32mi:
    case X86::XOR32mi8:
    case X86::XOR32mr:
    case X86::XOR64mi8:
    case X86::XOR64mi32:
    case X86::XOR64mr: {
      BinOpInst = BinaryOperator::CreateXor(LdInst, SrcValue);

      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::DEC8m:
    case X86::DEC16m:
    case X86::DEC32m:
    case X86::DEC64m: {
      BinOpInst = BinaryOperator::CreateSub(LdInst, SrcValue);

      AffectedEFlags.insert(EFLAGS::PF);
    } break;
    case X86::SAR8mCL:
    case X86::SAR16mCL:
    case X86::SAR32mCL:
    case X86::SAR64mCL:
    case X86::SHL8mCL:
    case X86::SHL16mCL:
    case X86::SHL32mCL:
    case X86::SHL64mCL:
    case X86::SHR8mCL:
    case X86::SHR16mCL:
    case X86::SHR32mCL:
    case X86::SHR64mCL: {
      Type *LdInstTy = LdInst->getType();
      // SrcValue is masked to 5 bits (6 bits if 64-bit register)
      bool Is64Bit = (LdInstTy->getPrimitiveSizeInBits() == 64);
      Value *CountMask = Is64Bit ? ConstantInt::get(LdInstTy, 0x1f)
                                 : ConstantInt::get(LdInstTy, 0x3f);
      // Generate mask
      auto CountValue = BinaryOperator::CreateAnd(SrcValue, CountMask,
                                             "shift-cnt-msk", RaisedBB);

      if (instrNameStartsWith(MI, "SAR")) {
        BinOpInst =
            BinaryOperator::CreateAShr(LdInst, CountValue);
      } else if (instrNameStartsWith(MI, "SHL")) {
        BinOpInst =
            BinaryOperator::CreateShl(LdInst, CountValue);
      } else if (instrNameStartsWith(MI, "SHR")) {
        BinOpInst =
            BinaryOperator::CreateLShr(LdInst, CountValue);
      } else {
        llvm_unreachable("unhandled shift instruction");
      }
    } break;
    case X86::SAR8mi:
    case X86::SAR16mi:
    case X86::SAR32mi:
    case X86::SAR64mi: {
      BinOpInst = BinaryOperator::CreateLShr(LdInst, SrcValue);
    } break;
    case X86::SHL8mi:
    case X86::SHL16mi:
    case X86::SHL32mi:
    case X86::SHL64mi: {
      BinOpInst = BinaryOperator::CreateShl(LdInst, SrcValue);
    } break;
    case X86::SHR8mi:
    case X86::SHR16mi:
    case X86::SHR32mi:
    case X86::SHR64mi: {
      BinOpInst = BinaryOperator::CreateLShr(LdInst, SrcValue);
    } break;
    default:
      assert(false && "Unhandled non-move mem op instruction");
    }

    RaisedBB->getInstList().push_back(BinOpInst);

    SrcValue = BinOpInst;

    // Test and set affected flags
    for (auto Flag : AffectedEFlags)
      raisedValues->testAndSetEflagSSAValue(Flag, MI, BinOpInst);
  }

  assert((SrcValue != nullptr) && "Unexpected null value to be stored while "
                                  "raising binary mem op instruction");
  // Store resultant value
  new StoreInst(SrcValue, MemRefVal, false, Align(), RaisedBB);

  return true;
}