1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "insn.h"
17 #include "isa.h"
18 #include "cg.h"
19 namespace maplebe {
IsMachineInstruction() const20 bool Insn::IsMachineInstruction() const
21 {
22     return md && md->IsPhysicalInsn() && Globals::GetInstance()->GetTarget()->IsTargetInsn(mOp);
23 }
24 
IsLoad() const25 bool Insn::IsLoad() const
26 {
27     DEBUG_ASSERT(md, " set insnDescription for insn ");
28     return md->IsLoad();
29 }
IsStore() const30 bool Insn::IsStore() const
31 {
32     DEBUG_ASSERT(md, " set insnDescription for insn ");
33     return md->IsStore();
34 }
IsMove() const35 bool Insn::IsMove() const
36 {
37     DEBUG_ASSERT(md, " set insnDescription for insn ");
38     return md->IsMove();
39 }
IsBranch() const40 bool Insn::IsBranch() const
41 {
42     DEBUG_ASSERT(md, " set insnDescription for insn ");
43     return md->IsBranch();
44 }
IsCondBranch() const45 bool Insn::IsCondBranch() const
46 {
47     DEBUG_ASSERT(md, " set insnDescription for insn ");
48     return md->IsCondBranch();
49 }
IsUnCondBranch() const50 bool Insn::IsUnCondBranch() const
51 {
52     DEBUG_ASSERT(md, " set insnDescription for insn ");
53     return md->IsUnCondBranch();
54 }
IsBasicOp() const55 bool Insn::IsBasicOp() const
56 {
57     DEBUG_ASSERT(md, " set insnDescription for insn ");
58     return md->IsBasicOp();
59 }
IsConversion() const60 bool Insn::IsConversion() const
61 {
62     DEBUG_ASSERT(md, " set insnDescription for insn ");
63     return md->IsConversion();
64 }
IsUnaryOp() const65 bool Insn::IsUnaryOp() const
66 {
67     DEBUG_ASSERT(md, " set insnDescription for insn ");
68     return md->IsUnaryOp();
69 }
IsShift() const70 bool Insn::IsShift() const
71 {
72     DEBUG_ASSERT(md, " set insnDescription for insn ");
73     return md->IsShift();
74 }
IsCall() const75 bool Insn::IsCall() const
76 {
77     DEBUG_ASSERT(md, " set insnDescription for insn ");
78     return md->IsCall();
79 }
IsSpecialCall() const80 bool Insn::IsSpecialCall() const
81 {
82     return md ? md->IsSpecialCall() : false;
83 }
IsTailCall() const84 bool Insn::IsTailCall() const
85 {
86     DEBUG_ASSERT(md, " set insnDescription for insn ");
87     return md->IsTailCall();
88 }
IsAsmInsn() const89 bool Insn::IsAsmInsn() const
90 {
91     DEBUG_ASSERT(md, " set insnDescription for insn ");
92     return md->IsInlineAsm();
93 }
IsAtomic() const94 bool Insn::IsAtomic() const
95 {
96     DEBUG_ASSERT(md, " set insnDescription for insn ");
97     return md->IsAtomic();
98 }
IsMemAccess() const99 bool Insn::IsMemAccess() const
100 {
101     DEBUG_ASSERT(md, " set insnDescription for insn ");
102     return md->IsMemAccess();
103 }
GetAtomicNum() const104 uint32 Insn::GetAtomicNum() const
105 {
106     DEBUG_ASSERT(md, " set insnDescription for insn ");
107     return md->GetAtomicNum();
108 }
IsSpecialIntrinsic() const109 bool Insn::IsSpecialIntrinsic() const
110 {
111     DEBUG_ASSERT(md, " set insnDescription for insn ");
112     return md->IsSpecialIntrinsic();
113 }
IsLoadStorePair() const114 bool Insn::IsLoadStorePair() const
115 {
116     DEBUG_ASSERT(md, " set insnDescription for insn ");
117     return md->IsLoadStorePair();
118 }
IsLoadLabel() const119 bool Insn::IsLoadLabel() const
120 {
121     return md->IsLoad() && GetOperand(kInsnSecondOpnd).GetKind() == Operand::kOpdBBAddress;
122 }
OpndIsDef(uint32 id) const123 bool Insn::OpndIsDef(uint32 id) const
124 {
125     DEBUG_ASSERT(md, " set insnDescription for insn ");
126     return md->GetOpndDes(id)->IsDef();
127 }
IsComment() const128 bool Insn::IsComment() const
129 {
130     return mOp == abstract::MOP_comment && !md->IsPhysicalInsn();
131 }
132 
IsImmaterialInsn() const133 bool Insn::IsImmaterialInsn() const
134 {
135     return IsComment();
136 }
137 
IsPseudo() const138 bool Insn::IsPseudo() const
139 {
140     return md && md->IsPhysicalInsn() && Globals::GetInstance()->GetTarget()->IsPseudoInsn(mOp);
141 }
142 
GetMemOpnd() const143 Operand *Insn::GetMemOpnd() const
144 {
145     for (uint32 i = 0; i < opnds.size(); ++i) {
146         Operand &opnd = GetOperand(i);
147         if (opnd.IsMemoryAccessOperand()) {
148             return &opnd;
149         }
150     }
151     return nullptr;
152 }
153 
IsRegDefined(regno_t regNO) const154 bool Insn::IsRegDefined(regno_t regNO) const
155 {
156     return GetDefRegs().count(regNO);
157 }
158 
GetDefRegs() const159 std::set<uint32> Insn::GetDefRegs() const
160 {
161     std::set<uint32> defRegNOs;
162     size_t opndNum = opnds.size();
163     for (uint32 i = 0; i < opndNum; ++i) {
164         Operand &opnd = GetOperand(i);
165         auto *regProp = md->opndMD[i];
166         bool isDef = regProp->IsDef();
167         if (!isDef && !opnd.IsMemoryAccessOperand()) {
168             continue;
169         }
170         if (opnd.IsList()) {
171             for (auto *op : static_cast<ListOperand &>(opnd).GetOperands()) {
172                 DEBUG_ASSERT(op != nullptr, "invalid operand in list operand");
173                 defRegNOs.emplace(op->GetRegisterNumber());
174             }
175         } else if (opnd.IsMemoryAccessOperand()) {
176             auto &memOpnd = static_cast<MemOperand &>(opnd);
177             RegOperand *base = memOpnd.GetBaseRegister();
178             if (base != nullptr) {
179                 if (memOpnd.GetAddrMode() == MemOperand::kAddrModeBOi &&
180                     (memOpnd.IsPostIndexed() || memOpnd.IsPreIndexed())) {
181                     DEBUG_ASSERT(!defRegNOs.count(base->GetRegisterNumber()), "duplicate def in one insn");
182                     defRegNOs.emplace(base->GetRegisterNumber());
183                 }
184             }
185         } else if (opnd.IsConditionCode() || opnd.IsRegister()) {
186             defRegNOs.emplace(static_cast<RegOperand &>(opnd).GetRegisterNumber());
187         }
188     }
189     return defRegNOs;
190 }
191 
CheckMD() const192 bool Insn::CheckMD() const
193 {
194 #ifdef ARK_LITECG_DEBUG
195     if (!md) {
196         LogInfo::MapleLogger() << " need machine description for target insn\n";
197         return false;
198     }
199     /* check if the number of operand(s) matches */
200     uint32 insnOperandSize = GetOperandSize();
201     if (insnOperandSize != md->GetOpndMDLength()) {
202         LogInfo::MapleLogger() << " need machine description for target insn\n";
203         return false;
204     }
205     /* check if the type of each operand  matches */
206     for (uint32 i = 0; i < insnOperandSize; ++i) {
207         Operand &opnd = GetOperand(i);
208         auto *opndDesc = md->GetOpndDes(i);
209         if (opnd.IsImmediate()) {
210             return opndDesc->IsImm();
211         } else {
212             return (opnd.GetKind() == opndDesc->GetOperandType());
213         }
214     }
215 #endif
216     return true;
217 }
218 
GetCallTargetOperand() const219 Operand *Insn::GetCallTargetOperand() const
220 {
221     DEBUG_ASSERT(IsCall() || IsTailCall(), "should be call");
222     return &GetOperand(kInsnFirstOpnd);
223 }
224 
CommuteOperands(uint32 dIndex, uint32 sIndex)225 void Insn::CommuteOperands(uint32 dIndex, uint32 sIndex)
226 {
227     Operand *tempCopy = opnds[sIndex];
228     opnds[sIndex] = opnds[dIndex];
229     opnds[dIndex] = tempCopy;
230 }
231 
GetMemoryByteSize() const232 uint32 Insn::GetMemoryByteSize() const
233 {
234     DEBUG_ASSERT(IsMemAccess(), "must be memory access insn");
235     uint32 res = 0;
236     for (size_t i = 0; i < opnds.size(); ++i) {
237         if (md->GetOpndDes(i)->GetOperandType() == Operand::kOpdMem) {
238             res = md->GetOpndDes(i)->GetSize();
239         }
240     }
241     DEBUG_ASSERT(res, "cannot access empty memory");
242     if (IsLoadStorePair()) {
243         res = res << 1;
244     }
245     res = res >> k8BitShift;
246     return res;
247 }
248 
ScanReg(regno_t regNO) const249 bool Insn::ScanReg(regno_t regNO) const
250 {
251     uint32 opndNum = GetOperandSize();
252     for (uint32 i = 0; i < opndNum; ++i) {
253         Operand &opnd = GetOperand(i);
254         if (opnd.IsList()) {
255             auto &listOpnd = static_cast<ListOperand &>(opnd);
256             for (auto listElem : listOpnd.GetOperands()) {
257                 auto *regOpnd = static_cast<RegOperand *>(listElem);
258                 DEBUG_ASSERT(regOpnd != nullptr, "parameter operand must be RegOperand");
259                 if (regNO == regOpnd->GetRegisterNumber()) {
260                     return true;
261                 }
262             }
263         } else if (opnd.IsMemoryAccessOperand()) {
264             auto &memOpnd = static_cast<MemOperand &>(opnd);
265             RegOperand *base = memOpnd.GetBaseRegister();
266             RegOperand *index = memOpnd.GetIndexRegister();
267             if ((base != nullptr && base->GetRegisterNumber() == regNO) ||
268                 (index != nullptr && index->GetRegisterNumber() == regNO)) {
269                 return true;
270             }
271         } else if (opnd.IsRegister()) {
272             if (static_cast<RegOperand &>(opnd).GetRegisterNumber() == regNO) {
273                 return true;
274             }
275         }
276     }
277     return false;
278 }
279 
SetMOP(const InsnDesc &idesc)280 void Insn::SetMOP(const InsnDesc &idesc)
281 {
282     mOp = idesc.GetOpc();
283     md = &idesc;
284 }
285 
Dump() const286 void Insn::Dump() const
287 {
288 #ifdef ARK_LITECG_DEBUG
289     DEBUG_ASSERT(md != nullptr, "md should not be nullptr");
290     LogInfo::MapleLogger() << "< " << GetId() << " > ";
291     LogInfo::MapleLogger() << md->name << "(" << mOp << ")";
292 
293     for (uint32 i = 0; i < GetOperandSize(); ++i) {
294         Operand &opnd = GetOperand(i);
295         LogInfo::MapleLogger() << " (opnd" << i << ": ";
296         Globals::GetInstance()->GetTarget()->DumpTargetOperand(opnd, *md->GetOpndDes(i));
297         LogInfo::MapleLogger() << ")";
298     }
299 
300     if (stackMap != nullptr) {
301         const auto &deoptVreg2Opnd = stackMap->GetDeoptInfo().GetDeoptBundleInfo();
302         if (!deoptVreg2Opnd.empty()) {
303             LogInfo::MapleLogger() << "  (deopt: ";
304             bool isFirstElem = true;
305             for (const auto &elem : deoptVreg2Opnd) {
306                 if (!isFirstElem) {
307                     LogInfo::MapleLogger() << ", ";
308                 } else {
309                     isFirstElem = false;
310                 }
311                 LogInfo::MapleLogger() << elem.first << ":";
312                 elem.second->Dump();
313             }
314             LogInfo::MapleLogger() << ")";
315         }
316     }
317     LogInfo::MapleLogger() << "\n";
318 #endif
319 }
320 }  // namespace maplebe
321