1*0b57cec5SDimitry Andric //===- MipsAnalyzeImmediate.cpp - Analyze Immediates ----------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "MipsAnalyzeImmediate.h" 10*0b57cec5SDimitry Andric #include "Mips.h" 11*0b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 12*0b57cec5SDimitry Andric #include <cassert> 13*0b57cec5SDimitry Andric #include <cstdint> 14*0b57cec5SDimitry Andric #include <iterator> 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric using namespace llvm; 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {} 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric // Add I to the instruction sequences. 21*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) { 22*0b57cec5SDimitry Andric // Add an instruction seqeunce consisting of just I. 23*0b57cec5SDimitry Andric if (SeqLs.empty()) { 24*0b57cec5SDimitry Andric SeqLs.push_back(InstSeq(1, I)); 25*0b57cec5SDimitry Andric return; 26*0b57cec5SDimitry Andric } 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric for (InstSeqLs::iterator Iter = SeqLs.begin(); Iter != SeqLs.end(); ++Iter) 29*0b57cec5SDimitry Andric Iter->push_back(I); 30*0b57cec5SDimitry Andric } 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, 33*0b57cec5SDimitry Andric InstSeqLs &SeqLs) { 34*0b57cec5SDimitry Andric GetInstSeqLs((Imm + 0x8000ULL) & 0xffffffffffff0000ULL, RemSize, SeqLs); 35*0b57cec5SDimitry Andric AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffffULL)); 36*0b57cec5SDimitry Andric } 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, 39*0b57cec5SDimitry Andric InstSeqLs &SeqLs) { 40*0b57cec5SDimitry Andric GetInstSeqLs(Imm & 0xffffffffffff0000ULL, RemSize, SeqLs); 41*0b57cec5SDimitry Andric AddInstr(SeqLs, Inst(ORi, Imm & 0xffffULL)); 42*0b57cec5SDimitry Andric } 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, 45*0b57cec5SDimitry Andric InstSeqLs &SeqLs) { 46*0b57cec5SDimitry Andric unsigned Shamt = countTrailingZeros(Imm); 47*0b57cec5SDimitry Andric GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs); 48*0b57cec5SDimitry Andric AddInstr(SeqLs, Inst(SLL, Shamt)); 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::GetInstSeqLs(uint64_t Imm, unsigned RemSize, 52*0b57cec5SDimitry Andric InstSeqLs &SeqLs) { 53*0b57cec5SDimitry Andric uint64_t MaskedImm = Imm & (0xffffffffffffffffULL >> (64 - Size)); 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric // Do nothing if Imm is 0. 56*0b57cec5SDimitry Andric if (!MaskedImm) 57*0b57cec5SDimitry Andric return; 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric // A single ADDiu will do if RemSize <= 16. 60*0b57cec5SDimitry Andric if (RemSize <= 16) { 61*0b57cec5SDimitry Andric AddInstr(SeqLs, Inst(ADDiu, MaskedImm)); 62*0b57cec5SDimitry Andric return; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric // Shift if the lower 16-bit is cleared. 66*0b57cec5SDimitry Andric if (!(Imm & 0xffff)) { 67*0b57cec5SDimitry Andric GetInstSeqLsSLL(Imm, RemSize, SeqLs); 68*0b57cec5SDimitry Andric return; 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric GetInstSeqLsADDiu(Imm, RemSize, SeqLs); 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric // If bit 15 is cleared, it doesn't make a difference whether the last 74*0b57cec5SDimitry Andric // instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi. 75*0b57cec5SDimitry Andric if (Imm & 0x8000) { 76*0b57cec5SDimitry Andric InstSeqLs SeqLsORi; 77*0b57cec5SDimitry Andric GetInstSeqLsORi(Imm, RemSize, SeqLsORi); 78*0b57cec5SDimitry Andric SeqLs.append(std::make_move_iterator(SeqLsORi.begin()), 79*0b57cec5SDimitry Andric std::make_move_iterator(SeqLsORi.end())); 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric // Replace a ADDiu & SLL pair with a LUi. 84*0b57cec5SDimitry Andric // e.g. the following two instructions 85*0b57cec5SDimitry Andric // ADDiu 0x0111 86*0b57cec5SDimitry Andric // SLL 18 87*0b57cec5SDimitry Andric // are replaced with 88*0b57cec5SDimitry Andric // LUi 0x444 89*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) { 90*0b57cec5SDimitry Andric // Check if the first two instructions are ADDiu and SLL and the shift amount 91*0b57cec5SDimitry Andric // is at least 16. 92*0b57cec5SDimitry Andric if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) || 93*0b57cec5SDimitry Andric (Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16)) 94*0b57cec5SDimitry Andric return; 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric // Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit. 97*0b57cec5SDimitry Andric int64_t Imm = SignExtend64<16>(Seq[0].ImmOpnd); 98*0b57cec5SDimitry Andric int64_t ShiftedImm = (uint64_t)Imm << (Seq[1].ImmOpnd - 16); 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric if (!isInt<16>(ShiftedImm)) 101*0b57cec5SDimitry Andric return; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric // Replace the first instruction and erase the second. 104*0b57cec5SDimitry Andric Seq[0].Opc = LUi; 105*0b57cec5SDimitry Andric Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff); 106*0b57cec5SDimitry Andric Seq.erase(Seq.begin() + 1); 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) { 110*0b57cec5SDimitry Andric InstSeqLs::iterator ShortestSeq = SeqLs.end(); 111*0b57cec5SDimitry Andric // The length of an instruction sequence is at most 7. 112*0b57cec5SDimitry Andric unsigned ShortestLength = 8; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) { 115*0b57cec5SDimitry Andric ReplaceADDiuSLLWithLUi(*S); 116*0b57cec5SDimitry Andric assert(S->size() <= 7); 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric if (S->size() < ShortestLength) { 119*0b57cec5SDimitry Andric ShortestSeq = S; 120*0b57cec5SDimitry Andric ShortestLength = S->size(); 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric Insts.clear(); 125*0b57cec5SDimitry Andric Insts.append(ShortestSeq->begin(), ShortestSeq->end()); 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric const MipsAnalyzeImmediate::InstSeq 129*0b57cec5SDimitry Andric &MipsAnalyzeImmediate::Analyze(uint64_t Imm, unsigned Size, 130*0b57cec5SDimitry Andric bool LastInstrIsADDiu) { 131*0b57cec5SDimitry Andric this->Size = Size; 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric if (Size == 32) { 134*0b57cec5SDimitry Andric ADDiu = Mips::ADDiu; 135*0b57cec5SDimitry Andric ORi = Mips::ORi; 136*0b57cec5SDimitry Andric SLL = Mips::SLL; 137*0b57cec5SDimitry Andric LUi = Mips::LUi; 138*0b57cec5SDimitry Andric } else { 139*0b57cec5SDimitry Andric ADDiu = Mips::DADDiu; 140*0b57cec5SDimitry Andric ORi = Mips::ORi64; 141*0b57cec5SDimitry Andric SLL = Mips::DSLL; 142*0b57cec5SDimitry Andric LUi = Mips::LUi64; 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric InstSeqLs SeqLs; 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric // Get the list of instruction sequences. 148*0b57cec5SDimitry Andric if (LastInstrIsADDiu | !Imm) 149*0b57cec5SDimitry Andric GetInstSeqLsADDiu(Imm, Size, SeqLs); 150*0b57cec5SDimitry Andric else 151*0b57cec5SDimitry Andric GetInstSeqLs(Imm, Size, SeqLs); 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric // Set Insts to the shortest instruction sequence. 154*0b57cec5SDimitry Andric GetShortestSeq(SeqLs, Insts); 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric return Insts; 157*0b57cec5SDimitry Andric } 158