Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp
35294 views
//===- MipsAnalyzeImmediate.cpp - Analyze Immediates ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MipsAnalyzeImmediate.h"9#include "Mips.h"10#include "llvm/Support/MathExtras.h"11#include <cassert>12#include <cstdint>13#include <iterator>1415using namespace llvm;1617MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {}1819// Add I to the instruction sequences.20void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) {21// Add an instruction seqeunce consisting of just I.22if (SeqLs.empty()) {23SeqLs.push_back(InstSeq(1, I));24return;25}2627for (auto &S : SeqLs)28S.push_back(I);29}3031void MipsAnalyzeImmediate::GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize,32InstSeqLs &SeqLs) {33GetInstSeqLs((Imm + 0x8000ULL) & 0xffffffffffff0000ULL, RemSize, SeqLs);34AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffffULL));35}3637void MipsAnalyzeImmediate::GetInstSeqLsORi(uint64_t Imm, unsigned RemSize,38InstSeqLs &SeqLs) {39GetInstSeqLs(Imm & 0xffffffffffff0000ULL, RemSize, SeqLs);40AddInstr(SeqLs, Inst(ORi, Imm & 0xffffULL));41}4243void MipsAnalyzeImmediate::GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize,44InstSeqLs &SeqLs) {45unsigned Shamt = llvm::countr_zero(Imm);46GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs);47AddInstr(SeqLs, Inst(SLL, Shamt));48}4950void MipsAnalyzeImmediate::GetInstSeqLs(uint64_t Imm, unsigned RemSize,51InstSeqLs &SeqLs) {52uint64_t MaskedImm = Imm & (0xffffffffffffffffULL >> (64 - Size));5354// Do nothing if Imm is 0.55if (!MaskedImm)56return;5758// A single ADDiu will do if RemSize <= 16.59if (RemSize <= 16) {60AddInstr(SeqLs, Inst(ADDiu, MaskedImm));61return;62}6364// Shift if the lower 16-bit is cleared.65if (!(Imm & 0xffff)) {66GetInstSeqLsSLL(Imm, RemSize, SeqLs);67return;68}6970GetInstSeqLsADDiu(Imm, RemSize, SeqLs);7172// If bit 15 is cleared, it doesn't make a difference whether the last73// instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi.74if (Imm & 0x8000) {75InstSeqLs SeqLsORi;76GetInstSeqLsORi(Imm, RemSize, SeqLsORi);77SeqLs.append(std::make_move_iterator(SeqLsORi.begin()),78std::make_move_iterator(SeqLsORi.end()));79}80}8182// Replace a ADDiu & SLL pair with a LUi.83// e.g. the following two instructions84// ADDiu 0x011185// SLL 1886// are replaced with87// LUi 0x44488void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) {89// Check if the first two instructions are ADDiu and SLL and the shift amount90// is at least 16.91if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) ||92(Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16))93return;9495// Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit.96int64_t Imm = SignExtend64<16>(Seq[0].ImmOpnd);97int64_t ShiftedImm = (uint64_t)Imm << (Seq[1].ImmOpnd - 16);9899if (!isInt<16>(ShiftedImm))100return;101102// Replace the first instruction and erase the second.103Seq[0].Opc = LUi;104Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff);105Seq.erase(Seq.begin() + 1);106}107108void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) {109InstSeqLs::iterator ShortestSeq = SeqLs.end();110// The length of an instruction sequence is at most 7.111unsigned ShortestLength = 8;112113for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) {114ReplaceADDiuSLLWithLUi(*S);115assert(S->size() <= 7);116117if (S->size() < ShortestLength) {118ShortestSeq = S;119ShortestLength = S->size();120}121}122123Insts.clear();124Insts.append(ShortestSeq->begin(), ShortestSeq->end());125}126127const MipsAnalyzeImmediate::InstSeq128&MipsAnalyzeImmediate::Analyze(uint64_t Imm, unsigned Size,129bool LastInstrIsADDiu) {130this->Size = Size;131132if (Size == 32) {133ADDiu = Mips::ADDiu;134ORi = Mips::ORi;135SLL = Mips::SLL;136LUi = Mips::LUi;137} else {138ADDiu = Mips::DADDiu;139ORi = Mips::ORi64;140SLL = Mips::DSLL;141LUi = Mips::LUi64;142}143144InstSeqLs SeqLs;145146// Get the list of instruction sequences.147if (LastInstrIsADDiu | !Imm)148GetInstSeqLsADDiu(Imm, Size, SeqLs);149else150GetInstSeqLs(Imm, Size, SeqLs);151152// Set Insts to the shortest instruction sequence.153GetShortestSeq(SeqLs, Insts);154155return Insts;156}157158159