1//===-- MipsDirectObjLower.cpp - Mips LLVM direct object lowering -----===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains code to lower Mips MCInst records that are normally
11// left to the assembler to lower such as large shifts.
12//
13//===----------------------------------------------------------------------===//
14#include "MipsDirectObjLower.h"
15#include "MipsInstrInfo.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/MC/MCStreamer.h"
18
19using namespace llvm;
20
21// If the D<shift> instruction has a shift amount that is greater
22// than 31 (checked in calling routine), lower it to a D<shift>32 instruction
23void Mips::LowerLargeShift(MCInst& Inst) {
24
25  assert(Inst.getNumOperands() == 3 && "Invalid no. of operands for shift!");
26  assert(Inst.getOperand(2).isImm());
27
28  bool isLarge = false;
29  int64_t Shift;
30  Shift = Inst.getOperand(2).getImm();
31  if (Shift > 31) {
32    Shift -= 32;
33    isLarge = true;
34  }
35
36  // saminus32
37  (Inst.getOperand(2)).setImm(Shift);
38
39  if (isLarge)
40    switch (Inst.getOpcode()) {
41    default:
42      // Calling function is not synchronized
43      llvm_unreachable("Unexpected shift instruction");
44    case Mips::DSLL:
45      Inst.setOpcode(Mips::DSLL32);
46      return;
47    case Mips::DSRL:
48      Inst.setOpcode(Mips::DSRL32);
49      return;
50    case Mips::DSRA:
51      Inst.setOpcode(Mips::DSRA32);
52      return;
53    }
54}
55
56// Pick a DEXT or DINS instruction variant based on the pos and size operands
57void Mips::LowerDextDins(MCInst& InstIn) {
58  int Opcode = InstIn.getOpcode();
59
60  if (Opcode == Mips::DEXT)
61    assert(InstIn.getNumOperands() == 4 &&
62           "Invalid no. of machine operands for DEXT!");
63  else // Only DEXT and DINS are possible
64    assert(InstIn.getNumOperands() == 5 &&
65           "Invalid no. of machine operands for DINS!");
66
67  assert(InstIn.getOperand(2).isImm());
68  int64_t pos = InstIn.getOperand(2).getImm();
69  assert(InstIn.getOperand(3).isImm());
70  int64_t size = InstIn.getOperand(3).getImm();
71
72  if (size <= 32) {
73    if ((pos < 32)) { // DEXT/DINS, do nothing
74      return;
75    } else { // DEXTU/DINSU
76      InstIn.getOperand(2).setImm(pos - 32);
77      InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTU : Mips::DINSU);
78      return;
79    }
80  } else { // DEXTM/DINSM
81    assert(pos < 32 && "DEXT/DINS cannot have both size and pos > 32");
82    InstIn.getOperand(3).setImm(size - 32);
83    InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTM : Mips::DINSM);
84    return;
85  }
86}
87