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