MipsDirectObjLower.cpp   [plain text]


//===-- MipsDirectObjLower.cpp - Mips LLVM direct object lowering -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains code to lower Mips MCInst records that are normally
// left to the assembler to lower such as large shifts.
//
//===----------------------------------------------------------------------===//
#include "MipsDirectObjLower.h"
#include "MipsInstrInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"

using namespace llvm;

// If the D<shift> instruction has a shift amount that is greater
// than 31 (checked in calling routine), lower it to a D<shift>32 instruction
void Mips::LowerLargeShift(MCInst& Inst) {

  assert(Inst.getNumOperands() == 3 && "Invalid no. of operands for shift!");
  assert(Inst.getOperand(2).isImm());

  bool isLarge = false;
  int64_t Shift;
  Shift = Inst.getOperand(2).getImm();
  if (Shift > 31) {
    Shift -= 32;
    isLarge = true;
  }

  // saminus32
  (Inst.getOperand(2)).setImm(Shift);

  if (isLarge)
    switch (Inst.getOpcode()) {
    default:
      // Calling function is not synchronized
      llvm_unreachable("Unexpected shift instruction");
    case Mips::DSLL:
      Inst.setOpcode(Mips::DSLL32);
      return;
    case Mips::DSRL:
      Inst.setOpcode(Mips::DSRL32);
      return;
    case Mips::DSRA:
      Inst.setOpcode(Mips::DSRA32);
      return;
    }
}

// Pick a DEXT or DINS instruction variant based on the pos and size operands
void Mips::LowerDextDins(MCInst& InstIn) {
  int Opcode = InstIn.getOpcode();

  if (Opcode == Mips::DEXT)
    assert(InstIn.getNumOperands() == 4 &&
           "Invalid no. of machine operands for DEXT!");
  else // Only DEXT and DINS are possible
    assert(InstIn.getNumOperands() == 5 &&
           "Invalid no. of machine operands for DINS!");

  assert(InstIn.getOperand(2).isImm());
  int64_t pos = InstIn.getOperand(2).getImm();
  assert(InstIn.getOperand(3).isImm());
  int64_t size = InstIn.getOperand(3).getImm();

  if (size <= 32) {
    if ((pos < 32)) { // DEXT/DINS, do nothing
      return;
    } else { // DEXTU/DINSU
      InstIn.getOperand(2).setImm(pos - 32);
      InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTU : Mips::DINSU);
      return;
    }
  } else { // DEXTM/DINSM
    assert(pos < 32 && "DEXT/DINS cannot have both size and pos > 32");
    InstIn.getOperand(3).setImm(size - 32);
    InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTM : Mips::DINSM);
    return;
  }
}