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 kInsnIsBinaryOp,
59 kInsnIsPhi,
60 kInsnIsUnaryOp,
61 kInsnIsShift,
62 kInsnInlineAsm,
63 kInsnSpecialIntrisic,
64 kInsnIsNop,
65 kInsnIntrinsic,
66 kInsnIsBreakPoint,
67 };
68 using regno_t = uint32_t;
69 #define ISABSTRACT 1ULL
70 #define ISMOVE (1ULL << kInsnIsMove)
71 #define ISLOAD (1ULL << kInsnIsLoad)
72 #define ISLOADPAIR (1ULL << kInsnIsLoadPair)
73 #define ISSTORE (1ULL << kInsnIsStore)
74 #define ISSTOREPAIR (1ULL << kInsnIsStorePair)
75 #define ISLOADADDR (1ULL << kInsnIsLoadAddress)
76 #define ISATOMIC (1ULL << kInsnIsAtomic)
77 #define ISCALL (1ULL << kInsnIsCall)
78 #define ISSPCALL (1ULL << kInsnIsSpecialCall)
79 #define ISTAILCALL (1ULL << kInsnIsTailCall)
80 #define ISCONVERSION (1ULL << kInsnIsConversion)
81 #define ISCONDDEF (1ULL << kInsnIsCondDef)
82 #define HASACQUIRE (1ULL << kInsnHasAcqure)
83 #define HASACQUIRERCPC (1ULL << kInsnHasAcqureRCpc)
84 #define HASLOACQUIRE (1ULL << kInsnHasLOAcqure)
85 #define HASRELEASE (1ULL << kInsnHasRelease)
86 #define HASLORELEASE (1ULL << kInsnHasLORelease)
87 #define CANTHROW (1ULL << kInsnCanThrow)
88 #define ISDMB (1ULL << kInsnIsDMB)
89 #define ISUNCONDBRANCH (1ULL << kInsnIsUnCondBr)
90 #define ISCONDBRANCH (1ULL << kInsnIsCondBr)
91 #define HASLOOP (1ULL << kInsnHasLoop)
92 #define ISBASICOP (1ULL << kInsnIsBinaryOp)
93 #define ISPHI (1ULL << kInsnIsPhi)
94 #define ISUNARYOP (1ULL << kInsnIsUnaryOp)
95 #define ISSHIFT (1ULL << kInsnIsShift)
96 #define INLINEASM (1ULL << kInsnInlineAsm)
97 #define SPINTRINSIC (1ULL << kInsnSpecialIntrisic)
98 #define ISNOP (1ULL << kInsnIsNop)
99 #define ISINTRINSIC (1ULL << kInsnIntrinsic)
100 #define ISBREAKPOINT (1ULL << kInsnIsBreakPoint)
101 constexpr maplebe::regno_t kInvalidRegNO = 0;
102
103 /*
104 * ARM64 has 32 int registes and 32 FP registers.
105 * AMD64/X86_64 has 16 int registes, and 16 FP registers.
106 * In either case, the corresponding calling conventions use
107 * the smaller number of caller-saved registers.
108 * 64 bit is not large enough?
109 */
110 using CsrBitset = uint64_t;
111
112 template <typename ParaType>
113 class ConstraintFunction {
114 public:
115 using CfPointer = bool (*)(ParaType);
CheckConstraint(CfPointer ccfunc,ParaType a)116 bool CheckConstraint(CfPointer ccfunc, ParaType a) const
117 {
118 return (*ccfunc)(a);
119 }
120 };
121
122 /*
123 * abstract machine instruction
124 * a lower-level maple IR which is aimed to represent general machine instruction for extreme cpus
125 * 1. Support conversion between all types and registers
126 * 2. Support conversion between memory and registers
127 * 3. Support three address basic operations
128 *
129 */
130 namespace abstract {
131 #define DEFINE_MOP(op, ...) op,
132 enum AbstractMOP_t : maple::uint32 {
133 #include "abstract_mmir.def"
134 kMopLast
135 };
136 #undef DEFINE_MOP
137 } // namespace abstract
138
139 enum EncodeType : uint8 {
140 kMovImm,
141 kMovReg,
142 kAddSubExtendReg,
143 kAddSubImm,
144 kAddSubShiftImm,
145 kAddSubReg,
146 kAddSubShiftReg,
147 kBitfield,
148 kExtract,
149 kBranchImm,
150 kBranchReg,
151 kCompareBranch,
152 kCondCompareImm,
153 kCondCompareReg,
154 kConditionalSelect,
155 kDataProcess1Src,
156 kDataProcess2Src,
157 kDataProcess3Src,
158 kFloatIntConversions,
159 kFloatCompare,
160 kFloatDataProcessing1,
161 kFloatDataProcessing2,
162 kFloatDataProcessing3,
163 kFloatImm,
164 kFloatCondSelect,
165 kLoadStoreReg,
166 kLoadStoreAR,
167 kLoadExclusive,
168 kLoadExclusivePair,
169 kStoreExclusive,
170 kStoreExclusivePair,
171 kLoadPair,
172 kStorePair,
173 kLoadStoreFloat,
174 kLoadPairFloat,
175 kStorePairFloat,
176 kLoadLiteralReg,
177 kLogicalReg,
178 kLogicalImm,
179 kMoveWide,
180 kPCRelAddr,
181 kAddPCRelAddr,
182 kBrkInsn,
183 kSystemInsn,
184 kTestBranch,
185 kCondBranch,
186 kUnknownEncodeType,
187 };
188
189 struct InsnDesc {
190 using ImmValidFunc = std::function<bool(const MapleVector<Operand *>)>;
191 using SplitFunc = std::function<void(Insn *, bool, InsnBuilder *, OperandBuilder *)>;
192
InsnDescInsnDesc193 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
194 const std::string &inFormat, uint32 anum)
195 : opc(op),
196 opndMD(opndmd),
197 properties(props),
198 latencyType(ltype),
199 name(inName),
200 format(inFormat),
201 atomicNum(anum) {};
202
203 // for hard-coded machine description.
InsnDescInsnDesc204 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
205 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, const SplitFunc &sFunc)
206 : opc(op),
207 opndMD(opndmd),
208 properties(props),
209 latencyType(ltype),
210 name(inName),
211 format(inFormat),
212 atomicNum(anum),
213 validFunc(vFunc),
214 splitFunc(sFunc) {};
215
216 // for hard-coded machine description.
InsnDescInsnDesc217 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
218 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, const SplitFunc &sFunc,
219 EncodeType type, uint32 encode)
220 : opc(op),
221 opndMD(opndmd),
222 properties(props),
223 latencyType(ltype),
224 name(inName),
225 format(inFormat),
226 atomicNum(anum),
227 validFunc(vFunc),
228 splitFunc(sFunc),
229 encodeType(type),
230 mopEncode(encode) {};
231
232 // for aarch64 assemble
InsnDescInsnDesc233 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
234 const std::string &inFormat, uint32 anum, const ImmValidFunc &vFunc, EncodeType type, uint32 encode)
235 : opc(op),
236 opndMD(opndmd),
237 properties(props),
238 latencyType(ltype),
239 name(inName),
240 format(inFormat),
241 atomicNum(anum),
242 validFunc(vFunc),
243 encodeType(type),
244 mopEncode(encode) {};
245
246 // for aarch64 assemble
InsnDescInsnDesc247 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
248 const std::string &inFormat, uint32 anum, EncodeType type, uint32 encode)
249 : opc(op),
250 opndMD(opndmd),
251 properties(props),
252 latencyType(ltype),
253 name(inName),
254 format(inFormat),
255 atomicNum(anum),
256 encodeType(type),
257 mopEncode(encode) {};
258
259 MOperator opc;
260 std::vector<const OpndDesc *> opndMD;
261 uint64 properties;
262 uint32 latencyType;
263 const std::string name;
264 const std::string format;
265 uint32 atomicNum; /* indicate how many asm instructions it will emit. */
266 ImmValidFunc validFunc = nullptr; /* If insn has immOperand, this function needs to be implemented. */
267 // If insn needs to be split, this function needs to be implemented.
268 SplitFunc splitFunc = nullptr;
269 EncodeType encodeType = kUnknownEncodeType;
270 uint32 mopEncode = 0x00000000;
271
272 bool IsSame(const InsnDesc &left, std::function<bool(const InsnDesc &left, const InsnDesc &right)> cmp) const;
273
IsCallInsnDesc274 bool IsCall() const
275 {
276 return (properties & ISCALL) != 0;
277 }
278 // call insn does not obey standard call procedure!
IsSpecialCallInsnDesc279 bool IsSpecialCall() const
280 {
281 return (properties & ISSPCALL) != 0;
282 }
IsTailCallInsnDesc283 bool IsTailCall() const
284 {
285 return properties & ISTAILCALL;
286 }
IsPhiInsnDesc287 bool IsPhi() const
288 {
289 return (properties & ISPHI) != 0;
290 }
IsPhysicalInsnInsnDesc291 bool IsPhysicalInsn() const
292 {
293 return (properties & ISABSTRACT) == 0;
294 }
IsStoreInsnDesc295 bool IsStore() const
296 {
297 return (properties & ISSTORE) != 0;
298 }
IsLoadInsnDesc299 bool IsLoad() const
300 {
301 return (properties & ISLOAD) != 0;
302 }
IsConversionInsnDesc303 bool IsConversion() const
304 {
305 return (properties & ISCONVERSION) != 0;
306 }
IsLoadPairInsnDesc307 bool IsLoadPair() const
308 {
309 return (properties & (ISLOADPAIR)) != 0;
310 }
IsStorePairInsnDesc311 bool IsStorePair() const
312 {
313 return (properties & (ISSTOREPAIR)) != 0;
314 }
IsLoadStorePairInsnDesc315 bool IsLoadStorePair() const
316 {
317 return (properties & (ISLOADPAIR | ISSTOREPAIR)) != 0;
318 }
IsMoveInsnDesc319 bool IsMove() const
320 {
321 return (properties & ISMOVE) != 0;
322 }
IsDMBInsnDesc323 bool IsDMB() const
324 {
325 return (properties & (ISDMB)) != 0;
326 }
IsBasicOpInsnDesc327 bool IsBasicOp() const
328 {
329 return (properties & ISBASICOP) != 0;
330 }
IsCondBranchInsnDesc331 bool IsCondBranch() const
332 {
333 return (properties & (ISCONDBRANCH)) != 0;
334 }
IsUnCondBranchInsnDesc335 bool IsUnCondBranch() const
336 {
337 return (properties & (ISUNCONDBRANCH)) != 0;
338 }
IsLoadAddressInsnDesc339 bool IsLoadAddress() const
340 {
341 return (properties & (ISLOADADDR)) != 0;
342 }
IsAtomicInsnDesc343 bool IsAtomic() const
344 {
345 return (properties & ISATOMIC) != 0;
346 }
347
IsCondDefInsnDesc348 bool IsCondDef() const
349 {
350 return (properties & ISCONDDEF) != 0;
351 }
352
IsVolatileInsnDesc353 bool IsVolatile() const
354 {
355 return ((properties & HASRELEASE) != 0) || ((properties & HASACQUIRE) != 0);
356 }
357
IsMemAccessBarInsnDesc358 bool IsMemAccessBar() const
359 {
360 return (properties & (HASRELEASE | HASACQUIRE | HASACQUIRERCPC | HASLOACQUIRE | HASLORELEASE)) != 0;
361 }
362
IsMemAccessInsnDesc363 bool IsMemAccess() const
364 {
365 return (properties & (ISLOAD | ISSTORE | ISLOADPAIR | ISSTOREPAIR)) != 0;
366 }
367
IsBranchInsnDesc368 bool IsBranch() const
369 {
370 return (properties & (ISCONDBRANCH | ISUNCONDBRANCH)) != 0;
371 }
372
HasLoopInsnDesc373 bool HasLoop() const
374 {
375 return (properties & HASLOOP) != 0;
376 }
377
CanThrowInsnDesc378 bool CanThrow() const
379 {
380 return (properties & CANTHROW) != 0;
381 }
382
IsInlineAsmInsnDesc383 bool IsInlineAsm() const
384 {
385 return properties & INLINEASM;
386 }
387
IsSpecialIntrinsicInsnDesc388 bool IsSpecialIntrinsic() const
389 {
390 return properties & SPINTRINSIC;
391 }
392
IsIntrinsicInsnDesc393 bool IsIntrinsic() const
394 {
395 return properties & ISINTRINSIC;
396 }
397
GetOpcInsnDesc398 MOperator GetOpc() const
399 {
400 return opc;
401 }
402
VerifyInsnDesc403 bool Verify(const MapleVector<Operand *> &opnds) const
404 {
405 if (!validFunc) {
406 return true;
407 }
408 if (opnds.size() != opndMD.size()) {
409 CHECK_FATAL_FALSE("The size of opnds is wrong.");
410 }
411 return validFunc(opnds);
412 }
413
SplitInsnDesc414 void Split(Insn *insn, bool isAfterRegAlloc, InsnBuilder *insnBuilder, OperandBuilder *opndBuilder) const
415 {
416 if (!splitFunc) {
417 return;
418 }
419 splitFunc(insn, isAfterRegAlloc, insnBuilder, opndBuilder);
420 }
421
GetOpndDesInsnDesc422 const OpndDesc *GetOpndDes(size_t index) const
423 {
424 return opndMD[index];
425 }
426
GetOpndMDLengthInsnDesc427 uint32 GetOpndMDLength() const
428 {
429 return opndMD.size();
430 }
431
GetOperandSizeInsnDesc432 uint32 GetOperandSize() const
433 {
434 if (properties & (ISLOAD | ISSTORE)) {
435 /* use memory operand */
436 return GetOpndDes(1)->GetSize();
437 }
438 /* use dest operand */
439 return GetOpndDes(0)->GetSize();
440 }
441
Is64BitInsnDesc442 bool Is64Bit() const
443 {
444 return GetOperandSize() == k64BitSize;
445 }
446
GetLatencyTypeInsnDesc447 uint32 GetLatencyType() const
448 {
449 return latencyType;
450 }
451
IsUnaryOpInsnDesc452 bool IsUnaryOp() const
453 {
454 return (properties & ISUNARYOP) != 0;
455 }
456
IsShiftInsnDesc457 bool IsShift() const
458 {
459 return (properties & ISSHIFT) != 0;
460 }
461
GetNameInsnDesc462 const std::string &GetName() const
463 {
464 return name;
465 }
466
GetFormatInsnDesc467 const std::string &GetFormat() const
468 {
469 return format;
470 }
471
GetAtomicNumInsnDesc472 uint32 GetAtomicNum() const
473 {
474 return atomicNum;
475 }
476
IsBreakPointInsnDesc477 bool IsBreakPoint() const
478 {
479 return (properties & ISBREAKPOINT) != 0;
480 }
481
GetEncodeTypeInsnDesc482 EncodeType GetEncodeType() const
483 {
484 return encodeType;
485 }
486
GetMopEncodeInsnDesc487 uint32 GetMopEncode() const
488 {
489 return mopEncode;
490 }
491
GetAbstractIdInsnDesc492 static const InsnDesc &GetAbstractId(MOperator opc)
493 {
494 DEBUG_ASSERT(opc < abstract::kMopLast, "op must be lower than kMopLast");
495 return abstractId[opc];
496 }
497
498 static const InsnDesc abstractId[abstract::kMopLast];
499 };
500
501 enum RegAddress : uint32 { kRegHigh = 0x4, kRegLow = 0x8 };
502 constexpr uint32 kMemLow12 = 0x10;
503 constexpr uint32 kLiteralLow12 = kMemLow12;
504 constexpr uint32 kPreInc = 0x20;
505 constexpr uint32 kPostInc = 0x40;
506 constexpr uint32 kLoadLiteral = 0x80;
507
508 enum BitIndex : maple::uint8 {
509 k8BitIndex = 0,
510 k16BitIndex,
511 k32BitIndex,
512 k64BitIndex,
513 kBitIndexEnd,
514 };
515
GetBitIndex(uint32 bitSize)516 static inline BitIndex GetBitIndex(uint32 bitSize)
517 {
518 switch (bitSize) {
519 case k8BitSize:
520 return k8BitIndex;
521 case k16BitSize:
522 return k16BitIndex;
523 case k32BitSize:
524 return k32BitIndex;
525 case k64BitSize:
526 return k64BitIndex;
527 default:
528 CHECK_FATAL(false, "NIY, Not support size");
529 }
530 }
531 } /* namespace maplebe */
532
533 #endif /* MAPLEBE_INCLUDE_CG_ISA_H */
534