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