blob: 15c4282030dbb11ba8ca6813230d25fa357fcfaa [file] [log] [blame]
//===-- 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 "MipsInstrInfo.h"
#include "MCTargetDesc/MipsDirectObjLower.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());
int64_t Shift = Inst.getOperand(2).getImm();
if (Shift <= 31)
return; // Do nothing
Shift -= 32;
// saminus32
Inst.getOperand(2).setImm(Shift);
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;
// DEXTU/DINSU
InstIn.getOperand(2).setImm(pos - 32);
InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTU : Mips::DINSU);
return;
}
// 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;
}