Add class MipsAnalyzeImmediate which comes up with an instruction sequence to

load an immediate. 



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148900 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Akira Hatanaka 2012-01-25 01:43:36 +00:00
parent af7b4fb9be
commit dc81eae9d2
2 changed files with 215 additions and 0 deletions

View File

@ -0,0 +1,153 @@
//===-- MipsAnalyzeImmediate.cpp - Analyze immediates ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MipsAnalyzeImmediate.h"
#include "Mips.h"
#include "llvm/Support/MathExtras.h"
using namespace llvm;
MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {}
// Add I to the instruction sequences.
void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) {
// Add an instruction seqeunce consisting of just I.
if (SeqLs.empty()) {
SeqLs.push_back(InstSeq(1, I));
return;
}
for (InstSeqLs::iterator Iter = SeqLs.begin(); Iter != SeqLs.end(); ++Iter)
Iter->push_back(I);
}
void MipsAnalyzeImmediate::GetInstSeqLsADDiu(int64_t Imm, unsigned RemSize,
InstSeqLs &SeqLs) {
GetInstSeqLs((Imm + 0x8000) & ~0xffff, RemSize, SeqLs);
AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffff));
}
void MipsAnalyzeImmediate::GetInstSeqLsORi(int64_t Imm, unsigned RemSize,
InstSeqLs &SeqLs) {
GetInstSeqLs(Imm & ~0xffff, RemSize, SeqLs);
AddInstr(SeqLs, Inst(ORi, Imm & 0xffff));
}
void MipsAnalyzeImmediate::GetInstSeqLsSLL(int64_t Imm, unsigned RemSize,
InstSeqLs &SeqLs) {
unsigned Shamt = CountTrailingZeros_64(Imm);
GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs);
AddInstr(SeqLs, Inst(SLL, Shamt));
}
void MipsAnalyzeImmediate::GetInstSeqLs(int64_t Imm, unsigned RemSize,
InstSeqLs &SeqLs) {
int64_t MaskedImm = Imm & (((uint64_t)-1) >> (64 - Size));
// Do nothing if Imm is 0.
if (!MaskedImm)
return;
// A single ADDiu will do if RemSize <= 16.
if (RemSize <= 16) {
AddInstr(SeqLs, Inst(ADDiu, MaskedImm));
return;
}
// Shift if the lower 16-bit is cleared.
if (!(Imm & 0xffff)) {
GetInstSeqLsSLL(Imm, RemSize, SeqLs);
return;
}
GetInstSeqLsADDiu(Imm, RemSize, SeqLs);
// If bit 15 is cleared, it doesn't make a difference whether the last
// instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi.
if (Imm & 0x8000) {
InstSeqLs SeqLsORi;
GetInstSeqLsORi(Imm, RemSize, SeqLsORi);
SeqLs.insert(SeqLs.end(), SeqLsORi.begin(), SeqLsORi.end());
}
}
// Replace a ADDiu & SLL pair with a LUi.
// e.g. the following two instructions
// ADDiu 0x0111
// SLL 18
// are replaced with
// LUi 0x444
void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) {
// Check if the first two instructions are ADDiu and SLL and the shift amount
// is at least 16.
if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) ||
(Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16))
return;
// Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit.
int64_t Imm = (((int64_t)Seq[0].ImmOpnd) << 48) >> 48;
int64_t ShiftedImm = Imm << (Seq[1].ImmOpnd - 16);
if (!isInt<16>(ShiftedImm))
return;
// Replace the first instruction and erase the second.
Seq[0].Opc = LUi;
Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff);
Seq.erase(Seq.begin() + 1);
}
void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) {
InstSeqLs::iterator ShortestSeq = SeqLs.end();
// The length of an instruction sequence is at most 7.
unsigned ShortestLength = 8;
for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) {
ReplaceADDiuSLLWithLUi(*S);
assert(S->size() <= 7);
if (S->size() < ShortestLength) {
ShortestSeq = S;
ShortestLength = S->size();
}
}
Insts.clear();
Insts.append(ShortestSeq->begin(), ShortestSeq->end());
}
const MipsAnalyzeImmediate::InstSeq
&MipsAnalyzeImmediate::Analyze(int64_t Imm, unsigned Size,
bool LastInstrIsADDiu) {
this->Size = Size;
if (Size == 32) {
ADDiu = Mips::ADDiu;
ORi = Mips::ORi;
SLL = Mips::SLL;
LUi = Mips::LUi;
} else {
ADDiu = Mips::DADDiu;
ORi = Mips::ORi64;
SLL = Mips::DSLL;
LUi = Mips::LUi64;
}
InstSeqLs SeqLs;
// Get the list of instruction sequences.
if (LastInstrIsADDiu | !Imm)
GetInstSeqLsADDiu(Imm, Size, SeqLs);
else
GetInstSeqLs(Imm, Size, SeqLs);
// Set Insts to the shortest instruction sequence.
GetShortestSeq(SeqLs, Insts);
return Insts;
}

View File

@ -0,0 +1,62 @@
//===-- MipsAnalyzeImmediate.h - Analyze immediates -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MIPS_ANALYZE_IMMEDIATE_H
#define MIPS_ANALYZE_IMMEDIATE_H
#include "llvm/ADT/SmallVector.h"
namespace llvm {
class MipsAnalyzeImmediate {
public:
struct Inst {
unsigned Opc, ImmOpnd;
Inst(unsigned Opc, unsigned ImmOpnd);
};
typedef SmallVector<Inst, 7 > InstSeq;
/// Analyze - Get an instrucion sequence to load immediate Imm. The last
/// instruction in the sequence must be an ADDiu if LastInstrIsADDiu is
/// true;
const InstSeq &Analyze(int64_t Imm, unsigned Size, bool LastInstrIsADDiu);
private:
typedef SmallVector<InstSeq, 5> InstSeqLs;
/// AddInstr - Add I to all instruction sequences in SeqLs.
void AddInstr(InstSeqLs &SeqLs, const Inst &I);
/// GetInstSeqLsADDiu - Get instrucion sequences which end with an ADDiu to
/// load immediate Imm
void GetInstSeqLsADDiu(int64_t Imm, unsigned RemSize, InstSeqLs &SeqLs);
/// GetInstSeqLsORi - Get instrucion sequences which end with an ORi to
/// load immediate Imm
void GetInstSeqLsORi(int64_t Imm, unsigned RemSize, InstSeqLs &SeqLs);
/// GetInstSeqLsSLL - Get instrucion sequences which end with a SLL to
/// load immediate Imm
void GetInstSeqLsSLL(int64_t Imm, unsigned RemSize, InstSeqLs &SeqLs);
/// GetInstSeqLs - Get instrucion sequences to load immediate Imm.
void GetInstSeqLs(int64_t Imm, unsigned RemSize, InstSeqLs &SeqLs);
/// ReplaceADDiuSLLWithLUi - Replace an ADDiu & SLL pair with a LUi.
void ReplaceADDiuSLLWithLUi(InstSeq &Seq);
/// GetShortestSeq - Find the shortest instruction sequence in SeqLs and
/// return it in Insts.
void GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts);
unsigned Size;
unsigned ADDiu, ORi, SLL, LUi;
InstSeq Insts;
};
}
#endif