• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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