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 #ifndef MAPLEBE_INCLUDE_CG_ISA_H
17 #define MAPLEBE_INCLUDE_CG_ISA_H
18
19 #include <cstdint>
20 #include "types_def.h"
21 #include "operand.h"
22
23 namespace maplebe {
24 // For verify & split insn
25 #define VERIFY_INSN(INSN) (INSN)->VerifySelf()
26 #define SPLIT_INSN(INSN, FUNC) \
27 (INSN)->SplitSelf((FUNC)->IsAfterRegAlloc(), (FUNC)->GetInsnBuilder(), (FUNC)->GetOpndBuilder())
28
29 // circular dependency exists, no other choice
30 class Insn;
31 class InsnBuilder;
32 class OperandBuilder;
33
34 enum MopProperty : maple::uint8 {
35 kInsnIsAbstract,
36 kInsnIsMove,
37 kInsnIsLoad,
38 kInsnIsLoadPair,
39 kInsnIsStore,
40 kInsnIsStorePair,
41 kInsnIsLoadAddress,
42 kInsnIsAtomic,
43 kInsnIsCall,
44 kInsnIsSpecialCall,
45 kInsnIsTailCall,
46 kInsnIsConversion,
47 kInsnIsCondDef,
48 kInsnHasAcqure,
49 kInsnHasAcqureRCpc,
50 kInsnHasLOAcqure,
51 kInsnHasRelease,
52 kInsnHasLORelease,
53 kInsnCanThrow,
54 kInsnIsDMB,
55 kInsnIsUnCondBr,
56 kInsnIsCondBr,
57 kInsnHasLoop,
58 kInsnIsVectorOp,
59 kInsnIsBinaryOp,
60 kInsnIsPhi,
61 kInsnIsUnaryOp,
62 kInsnIsShift,
63 kInsnInlineAsm,
64 kInsnSpecialIntrisic,
65 kInsnIsNop,
66 kInsnIntrinsic,
67 kInsnIsBreakPoint,
68 };
69 using regno_t = uint32_t;
70 #define ISABSTRACT 1ULL
71 #define ISMOVE (1ULL << kInsnIsMove)
72 #define ISLOAD (1ULL << kInsnIsLoad)
73 #define ISLOADPAIR (1ULL << kInsnIsLoadPair)
74 #define ISSTORE (1ULL << kInsnIsStore)
75 #define ISSTOREPAIR (1ULL << kInsnIsStorePair)
76 #define ISLOADADDR (1ULL << kInsnIsLoadAddress)
77 #define ISATOMIC (1ULL << kInsnIsAtomic)
78 #define ISCALL (1ULL << kInsnIsCall)
79 #define ISSPCALL (1ULL << kInsnIsSpecialCall)
80 #define ISTAILCALL (1ULL << kInsnIsTailCall)
81 #define ISCONVERSION (1ULL << kInsnIsConversion)
82 #define ISCONDDEF (1ULL << kInsnIsCondDef)
83 #define HASACQUIRE (1ULL << kInsnHasAcqure)
84 #define HASACQUIRERCPC (1ULL << kInsnHasAcqureRCpc)
85 #define HASLOACQUIRE (1ULL << kInsnHasLOAcqure)
86 #define HASRELEASE (1ULL << kInsnHasRelease)
87 #define HASLORELEASE (1ULL << kInsnHasLORelease)
88 #define CANTHROW (1ULL << kInsnCanThrow)
89 #define ISDMB (1ULL << kInsnIsDMB)
90 #define ISUNCONDBRANCH (1ULL << kInsnIsUnCondBr)
91 #define ISCONDBRANCH (1ULL << kInsnIsCondBr)
92 #define HASLOOP (1ULL << kInsnHasLoop)
93 #define ISVECTOR (1ULL << kInsnIsVectorOp)
94 #define ISBASICOP (1ULL << kInsnIsBinaryOp)
95 #define ISPHI (1ULL << kInsnIsPhi)
96 #define ISUNARYOP (1ULL << kInsnIsUnaryOp)
97 #define ISSHIFT (1ULL << kInsnIsShift)
98 #define INLINEASM (1ULL << kInsnInlineAsm)
99 #define SPINTRINSIC (1ULL << kInsnSpecialIntrisic)
100 #define ISNOP (1ULL << kInsnIsNop)
101 #define ISINTRINSIC (1ULL << kInsnIntrinsic)
102 #define ISBREAKPOINT (1ULL << kInsnIsBreakPoint)
103 constexpr maplebe::regno_t kInvalidRegNO = 0;
104
105 /*
106 * ARM64 has 32 int registes and 32 FP registers.
107 * AMD64/X86_64 has 16 int registes, and 16 FP registers.
108 * In either case, the corresponding calling conventions use
109 * the smaller number of caller-saved registers.
110 * 64 bit is not large enough?
111 */
112 using CsrBitset = uint64_t;
113
114 template <typename ParaType>
115 class ConstraintFunction {
116 public:
117 using CfPointer = bool (*)(ParaType);
CheckConstraint(CfPointer ccfunc,ParaType a)118 bool CheckConstraint(CfPointer ccfunc, ParaType a) const
119 {
120 return (*ccfunc)(a);
121 }
122 };
123
124 /*
125 * abstract machine instruction
126 * a lower-level maple IR which is aimed to represent general machine instruction for extreme cpus
127 * 1. Support conversion between all types and registers
128 * 2. Support conversion between memory and registers
129 * 3. Support three address basic operations
130 *
131 */
132 namespace abstract {
133 #define DEFINE_MOP(op, ...) op,
134 enum AbstractMOP_t : maple::uint32 {
135 #include "abstract_mmir.def"
136 kMopLast
137 };
138 #undef DEFINE_MOP
139 } // namespace abstract
140
141 enum EncodeType : uint8 {
142 kMovImm,
143 kMovReg,
144 kAddSubExtendReg,
145 kAddSubImm,
146 kAddSubShiftImm,
147 kAddSubReg,
148 kAddSubShiftReg,
149 kBitfield,
150 kExtract,
151 kBranchImm,
152 kBranchReg,
153 kCompareBranch,
154 kCondCompareImm,
155 kCondCompareReg,
156 kConditionalSelect,
157 kDataProcess1Src,
158 kDataProcess2Src,
159 kDataProcess3Src,
160 kFloatIntConversions,
161 kFloatCompare,
162 kFloatDataProcessing1,
163 kFloatDataProcessing2,
164 kFloatDataProcessing3,
165 kFloatImm,
166 kFloatCondSelect,
167 kLoadStoreReg,
168 kLoadStoreAR,
169 kLoadExclusive,
170 kLoadExclusivePair,
171 kStoreExclusive,
172 kStoreExclusivePair,
173 kLoadPair,
174 kStorePair,
175 kLoadStoreFloat,
176 kLoadPairFloat,
177 kStorePairFloat,
178 kLoadLiteralReg,
179 kLogicalReg,
180 kLogicalImm,
181 kMoveWide,
182 kPCRelAddr,
183 kAddPCRelAddr,
184 kBrkInsn,
185 kSystemInsn,
186 kTestBranch,
187 kCondBranch,
188 kUnknownEncodeType,
189 };
190
191 struct InsnDesc {
192 using ImmValidFunc = std::function<bool(const MapleVector<Operand *>)>;
193 using SplitFunc = std::function<void(Insn *, bool, InsnBuilder *, OperandBuilder *)>;
194
InsnDescInsnDesc195 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
196 const std::string &inFormat, uint32 anum)
197 : opc(op),
198 opndMD(opndmd),
199 properties(props),
200 latencyType(ltype),
201 name(inName),
202 format(inFormat),
203 atomicNum(anum) {};
204
205 // for hard-coded machine description.
InsnDescInsnDesc206 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
207 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, const SplitFunc &sFunc)
208 : opc(op),
209 opndMD(opndmd),
210 properties(props),
211 latencyType(ltype),
212 name(inName),
213 format(inFormat),
214 atomicNum(anum),
215 validFunc(vFunc),
216 splitFunc(sFunc) {};
217
218 // for hard-coded machine description.
InsnDescInsnDesc219 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
220 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, const SplitFunc &sFunc,
221 EncodeType type, uint32 encode)
222 : opc(op),
223 opndMD(opndmd),
224 properties(props),
225 latencyType(ltype),
226 name(inName),
227 format(inFormat),
228 atomicNum(anum),
229 validFunc(vFunc),
230 splitFunc(sFunc),
231 encodeType(type),
232 mopEncode(encode) {};
233
234 // for aarch64 assemble
InsnDescInsnDesc235 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
236 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, EncodeType type, uint32 encode)
237 : opc(op),
238 opndMD(opndmd),
239 properties(props),
240 latencyType(ltype),
241 name(inName),
242 format(inFormat),
243 atomicNum(anum),
244 validFunc(vFunc),
245 encodeType(type),
246 mopEncode(encode) {};
247
248 // for aarch64 assemble
InsnDescInsnDesc249 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
250 const std::string &inFormat, uint32 anum, EncodeType type, uint32 encode)
251 : opc(op),
252 opndMD(opndmd),
253 properties(props),
254 latencyType(ltype),
255 name(inName),
256 format(inFormat),
257 atomicNum(anum),
258 encodeType(type),
259 mopEncode(encode) {};
260
261 MOperator opc;
262 std::vector<const OpndDesc *> opndMD;
263 uint64 properties;
264 uint32 latencyType;
265 const std::string name;
266 const std::string format;
267 uint32 atomicNum; /* indicate how many asm instructions it will emit. */
268 ImmValidFunc validFunc = nullptr; /* If insn has immOperand, this function needs to be implemented. */
269 // If insn needs to be split, this function needs to be implemented.
270 SplitFunc splitFunc = nullptr;
271 EncodeType encodeType = kUnknownEncodeType;
272 uint32 mopEncode = 0x00000000;
273
274 bool IsSame(const InsnDesc &left, std::function<bool(const InsnDesc &left, const InsnDesc &right)> cmp) const;
275
IsCallInsnDesc276 bool IsCall() const
277 {
278 return (properties & ISCALL) != 0;
279 }
280 // call insn does not obey standard call procedure!
IsSpecialCallInsnDesc281 bool IsSpecialCall() const
282 {
283 return (properties & ISSPCALL) != 0;
284 }
IsTailCallInsnDesc285 bool IsTailCall() const
286 {
287 return properties & ISTAILCALL;
288 }
IsPhiInsnDesc289 bool IsPhi() const
290 {
291 return (properties & ISPHI) != 0;
292 }
IsPhysicalInsnInsnDesc293 bool IsPhysicalInsn() const
294 {
295 return (properties & ISABSTRACT) == 0;
296 }
IsStoreInsnDesc297 bool IsStore() const
298 {
299 return (properties & ISSTORE) != 0;
300 }
IsLoadInsnDesc301 bool IsLoad() const
302 {
303 return (properties & ISLOAD) != 0;
304 }
IsConversionInsnDesc305 bool IsConversion() const
306 {
307 return (properties & ISCONVERSION) != 0;
308 }
IsLoadPairInsnDesc309 bool IsLoadPair() const
310 {
311 return (properties & (ISLOADPAIR)) != 0;
312 }
IsStorePairInsnDesc313 bool IsStorePair() const
314 {
315 return (properties & (ISSTOREPAIR)) != 0;
316 }
IsLoadStorePairInsnDesc317 bool IsLoadStorePair() const
318 {
319 return (properties & (ISLOADPAIR | ISSTOREPAIR)) != 0;
320 }
IsMoveInsnDesc321 bool IsMove() const
322 {
323 return (properties & ISMOVE) != 0;
324 }
IsDMBInsnDesc325 bool IsDMB() const
326 {
327 return (properties & (ISDMB)) != 0;
328 }
IsBasicOpInsnDesc329 bool IsBasicOp() const
330 {
331 return (properties & ISBASICOP) != 0;
332 }
IsCondBranchInsnDesc333 bool IsCondBranch() const
334 {
335 return (properties & (ISCONDBRANCH)) != 0;
336 }
IsUnCondBranchInsnDesc337 bool IsUnCondBranch() const
338 {
339 return (properties & (ISUNCONDBRANCH)) != 0;
340 }
IsLoadAddressInsnDesc341 bool IsLoadAddress() const
342 {
343 return (properties & (ISLOADADDR)) != 0;
344 }
IsAtomicInsnDesc345 bool IsAtomic() const
346 {
347 return (properties & ISATOMIC) != 0;
348 }
349
IsCondDefInsnDesc350 bool IsCondDef() const
351 {
352 return (properties & ISCONDDEF) != 0;
353 }
354
IsVectorOpInsnDesc355 bool IsVectorOp() const
356 {
357 return (properties & ISVECTOR) != 0;
358 }
359
IsVolatileInsnDesc360 bool IsVolatile() const
361 {
362 return ((properties & HASRELEASE) != 0) || ((properties & HASACQUIRE) != 0);
363 }
364
IsMemAccessBarInsnDesc365 bool IsMemAccessBar() const
366 {
367 return (properties & (HASRELEASE | HASACQUIRE | HASACQUIRERCPC | HASLOACQUIRE | HASLORELEASE)) != 0;
368 }
369
IsMemAccessInsnDesc370 bool IsMemAccess() const
371 {
372 return (properties & (ISLOAD | ISSTORE | ISLOADPAIR | ISSTOREPAIR)) != 0;
373 }
374
IsBranchInsnDesc375 bool IsBranch() const
376 {
377 return (properties & (ISCONDBRANCH | ISUNCONDBRANCH)) != 0;
378 }
379
HasLoopInsnDesc380 bool HasLoop() const
381 {
382 return (properties & HASLOOP) != 0;
383 }
384
CanThrowInsnDesc385 bool CanThrow() const
386 {
387 return (properties & CANTHROW) != 0;
388 }
389
IsInlineAsmInsnDesc390 bool IsInlineAsm() const
391 {
392 return properties & INLINEASM;
393 }
394
IsSpecialIntrinsicInsnDesc395 bool IsSpecialIntrinsic() const
396 {
397 return properties & SPINTRINSIC;
398 }
399
IsIntrinsicInsnDesc400 bool IsIntrinsic() const
401 {
402 return properties & ISINTRINSIC;
403 }
404
GetOpcInsnDesc405 MOperator GetOpc() const
406 {
407 return opc;
408 }
409
VerifyInsnDesc410 bool Verify(const MapleVector<Operand *> &opnds) const
411 {
412 if (!validFunc) {
413 return true;
414 }
415 if (opnds.size() != opndMD.size()) {
416 CHECK_FATAL_FALSE("The size of opnds is wrong.");
417 }
418 return validFunc(opnds);
419 }
420
SplitInsnDesc421 void Split(Insn *insn, bool isAfterRegAlloc, InsnBuilder *insnBuilder, OperandBuilder *opndBuilder) const
422 {
423 if (!splitFunc) {
424 return;
425 }
426 splitFunc(insn, isAfterRegAlloc, insnBuilder, opndBuilder);
427 }
428
GetOpndDesInsnDesc429 const OpndDesc *GetOpndDes(size_t index) const
430 {
431 return opndMD[index];
432 }
433
GetOpndMDLengthInsnDesc434 uint32 GetOpndMDLength() const
435 {
436 return opndMD.size();
437 }
438
GetOperandSizeInsnDesc439 uint32 GetOperandSize() const
440 {
441 if (properties & (ISLOAD | ISSTORE)) {
442 /* use memory operand */
443 return GetOpndDes(1)->GetSize();
444 }
445 /* use dest operand */
446 return GetOpndDes(0)->GetSize();
447 }
448
Is64BitInsnDesc449 bool Is64Bit() const
450 {
451 return GetOperandSize() == k64BitSize;
452 }
453
GetLatencyTypeInsnDesc454 uint32 GetLatencyType() const
455 {
456 return latencyType;
457 }
458
IsUnaryOpInsnDesc459 bool IsUnaryOp() const
460 {
461 return (properties & ISUNARYOP) != 0;
462 }
463
IsShiftInsnDesc464 bool IsShift() const
465 {
466 return (properties & ISSHIFT) != 0;
467 }
468
GetNameInsnDesc469 const std::string &GetName() const
470 {
471 return name;
472 }
473
GetFormatInsnDesc474 const std::string &GetFormat() const
475 {
476 return format;
477 }
478
GetAtomicNumInsnDesc479 uint32 GetAtomicNum() const
480 {
481 return atomicNum;
482 }
483
IsBreakPointInsnDesc484 bool IsBreakPoint() const
485 {
486 return (properties & ISBREAKPOINT) != 0;
487 }
488
GetEncodeTypeInsnDesc489 EncodeType GetEncodeType() const
490 {
491 return encodeType;
492 }
493
GetMopEncodeInsnDesc494 uint32 GetMopEncode() const
495 {
496 return mopEncode;
497 }
498
GetAbstractIdInsnDesc499 static const InsnDesc &GetAbstractId(MOperator opc)
500 {
501 DEBUG_ASSERT(opc < abstract::kMopLast, "op must be lower than kMopLast");
502 return abstractId[opc];
503 }
504
505 static const InsnDesc abstractId[abstract::kMopLast];
506 };
507
508 enum RegAddress : uint32 { kRegHigh = 0x4, kRegLow = 0x8 };
509 constexpr uint32 kMemLow12 = 0x10;
510 constexpr uint32 kLiteralLow12 = kMemLow12;
511 constexpr uint32 kPreInc = 0x20;
512 constexpr uint32 kPostInc = 0x40;
513 constexpr uint32 kLoadLiteral = 0x80;
514
515 enum BitIndex : maple::uint8 {
516 k8BitIndex = 0,
517 k16BitIndex,
518 k32BitIndex,
519 k64BitIndex,
520 kBitIndexEnd,
521 };
522
GetBitIndex(uint32 bitSize)523 static inline BitIndex GetBitIndex(uint32 bitSize)
524 {
525 switch (bitSize) {
526 case k8BitSize:
527 return k8BitIndex;
528 case k16BitSize:
529 return k16BitIndex;
530 case k32BitSize:
531 return k32BitIndex;
532 case k64BitSize:
533 return k64BitIndex;
534 default:
535 CHECK_FATAL(false, "NIY, Not support size");
536 }
537 }
538 } /* namespace maplebe */
539
540 #endif /* MAPLEBE_INCLUDE_CG_ISA_H */
541