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 enum MopProperty : maple::uint8 {
25 kInsnIsAbstract,
26 kInsnIsMove,
27 kInsnIsLoad,
28 kInsnIsLoadPair,
29 kInsnIsStore,
30 kInsnIsStorePair,
31 kInsnIsAtomic,
32 kInsnIsCall,
33 kInsnIsTailCall,
34 kInsnIsConversion,
35 kInsnIsCondDef,
36 kInsnHasAcqure,
37 kInsnHasAcqureRCpc,
38 kInsnHasLOAcqure,
39 kInsnHasRelease,
40 kInsnHasLORelease,
41 kInsnCanThrow,
42 kInsnIsDMB,
43 kInsnIsUnCondBr,
44 kInsnIsCondBr,
45 kInsnHasLoop,
46 kInsnIsVectorOp,
47 kInsnIsBinaryOp,
48 kInsnIsPhi,
49 kInsnIsUnaryOp,
50 kInsnIsShift,
51 kInsnInlineAsm,
52 kInsnSpecialIntrisic,
53 kInsnIsNop,
54 kInsnIntrinsic,
55 };
56 using regno_t = uint32_t;
57 #define ISABSTRACT 1ULL
58 #define ISMOVE (1ULL << kInsnIsMove)
59 #define ISLOAD (1ULL << kInsnIsLoad)
60 #define ISLOADPAIR (1ULL << kInsnIsLoadPair)
61 #define ISSTORE (1ULL << kInsnIsStore)
62 #define ISSTOREPAIR (1ULL << kInsnIsStorePair)
63 #define ISATOMIC (1ULL << kInsnIsAtomic)
64 #define ISCALL (1ULL << kInsnIsCall)
65 #define ISTAILCALL (1ULL << kInsnIsTailCall)
66 #define ISCONVERSION (1ULL << kInsnIsConversion)
67 #define ISCONDDEF (1ULL << kInsnIsCondDef)
68 #define HASACQUIRE (1ULL << kInsnHasAcqure)
69 #define HASACQUIRERCPC (1ULL << kInsnHasAcqureRCpc)
70 #define HASLOACQUIRE (1ULL << kInsnHasLOAcqure)
71 #define HASRELEASE (1ULL << kInsnHasRelease)
72 #define HASLORELEASE (1ULL << kInsnHasLORelease)
73 #define CANTHROW (1ULL << kInsnCanThrow)
74 #define ISDMB (1ULL << kInsnIsDMB)
75 #define ISUNCONDBRANCH (1ULL << kInsnIsUnCondBr)
76 #define ISCONDBRANCH (1ULL << kInsnIsCondBr)
77 #define HASLOOP (1ULL << kInsnHasLoop)
78 #define ISVECTOR (1ULL << kInsnIsVectorOp)
79 #define ISBASICOP (1ULL << kInsnIsBinaryOp)
80 #define ISPHI (1ULL << kInsnIsPhi)
81 #define ISUNARYOP (1ULL << kInsnIsUnaryOp)
82 #define ISSHIFT (1ULL << kInsnIsShift)
83 #define INLINEASM (1ULL << kInsnInlineAsm)
84 #define SPINTRINSIC (1ULL << kInsnSpecialIntrisic)
85 #define ISNOP (1ULL << kInsnIsNop)
86 #define ISINTRINSIC (1ULL << kInsnIntrinsic)
87 constexpr maplebe::regno_t kInvalidRegNO = 0;
88
89 /*
90 * ARM64 has 32 int registes and 32 FP registers.
91 * AMD64/X86_64 has 16 int registes, and 16 FP registers.
92 * In either case, the corresponding calling conventions use
93 * the smaller number of caller-saved registers.
94 * 64 bit is not large enough?
95 */
96 using CsrBitset = uint64_t;
97
98 template <typename ParaType>
99 class ConstraintFunction {
100 public:
101 using cfPointer = bool (*)(ParaType);
CheckConstraint(cfPointer ccfunc,ParaType a)102 bool CheckConstraint(cfPointer ccfunc, ParaType a) const
103 {
104 return (*ccfunc)(a);
105 }
106 };
107
108 /*
109 * abstract machine instruction
110 * a lower-level maple IR which is aimed to represent general machine instruction for extreme cpus
111 * 1. Support conversion between all types and registers
112 * 2. Support conversion between memory and registers
113 * 3. Support three address basic operations
114 *
115 */
116 namespace abstract {
117 #define DEFINE_MOP(op, ...) op,
118 enum AbstractMOP_t : maple::uint32 {
119 #include "abstract_mmir.def"
120 kMopLast
121 };
122 #undef DEFINE_MOP
123 } // namespace abstract
124
125 enum EncodeType : uint8 {
126 kMovImm,
127 kMovReg,
128 kAddSubExtendReg,
129 kAddSubImm,
130 kAddSubShiftImm,
131 kAddSubReg,
132 kAddSubShiftReg,
133 kBitfield,
134 kExtract,
135 kBranchImm,
136 kBranchReg,
137 kCompareBranch,
138 kCondCompareImm,
139 kCondCompareReg,
140 kConditionalSelect,
141 kDataProcess1Src,
142 kDataProcess2Src,
143 kDataProcess3Src,
144 kFloatIntConversions,
145 kFloatCompare,
146 kFloatDataProcessing1,
147 kFloatDataProcessing2,
148 kFloatDataProcessing3,
149 kFloatImm,
150 kFloatCondSelect,
151 kLoadStoreReg,
152 kLoadStoreAR,
153 kLoadExclusive,
154 kLoadExclusivePair,
155 kStoreExclusive,
156 kStoreExclusivePair,
157 kLoadPair,
158 kStorePair,
159 kLoadStoreFloat,
160 kLoadPairFloat,
161 kStorePairFloat,
162 kLoadLiteralReg,
163 kLogicalReg,
164 kLogicalImm,
165 kMoveWide,
166 kPCRelAddr,
167 kAddPCRelAddr,
168 kSystemInsn,
169 kTestBranch,
170 kCondBranch,
171 kUnknownEncodeType,
172 };
173
174 struct InsnDesc {
InsnDescInsnDesc175 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
176 const std::string &inFormat, uint32 anum)
177 : opc(op),
178 opndMD(opndmd),
179 properties(props),
180 latencyType(ltype),
181 name(inName),
182 format(inFormat),
183 atomicNum(anum) {};
184
185 // for hard-coded machine description.
InsnDescInsnDesc186 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
187 const std::string &inFormat, uint32 anum, std::function<bool(int64)> vFunc)
188 : opc(op),
189 opndMD(opndmd),
190 properties(props),
191 latencyType(ltype),
192 name(inName),
193 format(inFormat),
194 atomicNum(anum),
195 validFunc(vFunc) {};
196
197 // for aarch64 assemble
InsnDescInsnDesc198 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
199 const std::string &inFormat, uint32 anum, std::function<bool(int64)> vFunc, EncodeType type, uint32 encode)
200 : opc(op),
201 opndMD(opndmd),
202 properties(props),
203 latencyType(ltype),
204 name(inName),
205 format(inFormat),
206 atomicNum(anum),
207 validFunc(vFunc),
208 encodeType(type),
209 mopEncode(encode) {};
210
211 // for aarch64 assemble
InsnDescInsnDesc212 InsnDesc(MOperator op, std::vector<const OpndDesc *> opndmd, uint64 props, uint64 ltype, const std::string &inName,
213 const std::string &inFormat, uint32 anum, EncodeType type, uint32 encode)
214 : opc(op),
215 opndMD(opndmd),
216 properties(props),
217 latencyType(ltype),
218 name(inName),
219 format(inFormat),
220 atomicNum(anum),
221 encodeType(type),
222 mopEncode(encode) {};
223
224 MOperator opc;
225 std::vector<const OpndDesc *> opndMD;
226 uint64 properties;
227 uint32 latencyType;
228 const std::string name;
229 const std::string format;
230 uint32 atomicNum; /* indicate how many asm instructions it will emit. */
231 std::function<bool(int64)> validFunc = nullptr; /* If insn has immOperand, this function needs to be implemented. */
232 EncodeType encodeType = kUnknownEncodeType;
233 uint32 mopEncode = 0x00000000;
234
235 bool IsSame(const InsnDesc &left, std::function<bool(const InsnDesc &left, const InsnDesc &right)> cmp) const;
236
IsCallInsnDesc237 bool IsCall() const
238 {
239 return (properties & ISCALL) != 0;
240 }
IsTailCallInsnDesc241 bool IsTailCall() const
242 {
243 return properties & ISTAILCALL;
244 }
IsPhiInsnDesc245 bool IsPhi() const
246 {
247 return (properties & ISPHI) != 0;
248 }
IsPhysicalInsnInsnDesc249 bool IsPhysicalInsn() const
250 {
251 return (properties & ISABSTRACT) == 0;
252 }
IsStoreInsnDesc253 bool IsStore() const
254 {
255 return (properties & ISSTORE) != 0;
256 }
IsLoadInsnDesc257 bool IsLoad() const
258 {
259 return (properties & ISLOAD) != 0;
260 }
IsConversionInsnDesc261 bool IsConversion() const
262 {
263 return (properties & ISCONVERSION) != 0;
264 }
IsLoadPairInsnDesc265 bool IsLoadPair() const
266 {
267 return (properties & (ISLOADPAIR)) != 0;
268 }
IsStorePairInsnDesc269 bool IsStorePair() const
270 {
271 return (properties & (ISSTOREPAIR)) != 0;
272 }
IsLoadStorePairInsnDesc273 bool IsLoadStorePair() const
274 {
275 return (properties & (ISLOADPAIR | ISSTOREPAIR)) != 0;
276 }
IsMoveInsnDesc277 bool IsMove() const
278 {
279 return (properties & ISMOVE) != 0;
280 }
IsDMBInsnDesc281 bool IsDMB() const
282 {
283 return (properties & (ISDMB)) != 0;
284 }
IsBasicOpInsnDesc285 bool IsBasicOp() const
286 {
287 return (properties & ISBASICOP) != 0;
288 }
IsCondBranchInsnDesc289 bool IsCondBranch() const
290 {
291 return (properties & (ISCONDBRANCH)) != 0;
292 }
IsUnCondBranchInsnDesc293 bool IsUnCondBranch() const
294 {
295 return (properties & (ISUNCONDBRANCH)) != 0;
296 }
IsAtomicInsnDesc297 bool IsAtomic() const
298 {
299 return (properties & ISATOMIC) != 0;
300 }
301
IsCondDefInsnDesc302 bool IsCondDef() const
303 {
304 return (properties & ISCONDDEF) != 0;
305 }
306
IsVectorOpInsnDesc307 bool IsVectorOp() const
308 {
309 return (properties & ISVECTOR) != 0;
310 }
311
IsVolatileInsnDesc312 bool IsVolatile() const
313 {
314 return ((properties & HASRELEASE) != 0) || ((properties & HASACQUIRE) != 0);
315 }
316
IsMemAccessBarInsnDesc317 bool IsMemAccessBar() const
318 {
319 return (properties & (HASRELEASE | HASACQUIRE | HASACQUIRERCPC | HASLOACQUIRE | HASLORELEASE)) != 0;
320 }
321
IsMemAccessInsnDesc322 bool IsMemAccess() const
323 {
324 return (properties & (ISLOAD | ISSTORE | ISLOADPAIR | ISSTOREPAIR)) != 0;
325 }
326
IsBranchInsnDesc327 bool IsBranch() const
328 {
329 return (properties & (ISCONDBRANCH | ISUNCONDBRANCH)) != 0;
330 }
331
HasLoopInsnDesc332 bool HasLoop() const
333 {
334 return (properties & HASLOOP) != 0;
335 }
336
CanThrowInsnDesc337 bool CanThrow() const
338 {
339 return (properties & CANTHROW) != 0;
340 }
341
IsInlineAsmInsnDesc342 bool IsInlineAsm() const
343 {
344 return properties & INLINEASM;
345 }
346
IsSpecialIntrinsicInsnDesc347 bool IsSpecialIntrinsic() const
348 {
349 return properties & SPINTRINSIC;
350 }
351
IsIntrinsicInsnDesc352 bool IsIntrinsic() const
353 {
354 return properties & ISINTRINSIC;
355 }
356
GetOpcInsnDesc357 MOperator GetOpc() const
358 {
359 return opc;
360 }
361
GetOpndDesInsnDesc362 const OpndDesc *GetOpndDes(size_t index) const
363 {
364 return opndMD[index];
365 }
366
GetOpndMDLengthInsnDesc367 uint32 GetOpndMDLength() const
368 {
369 return opndMD.size();
370 }
371
GetOperandSizeInsnDesc372 uint32 GetOperandSize() const
373 {
374 if (properties & (ISLOAD | ISSTORE)) {
375 /* use memory operand */
376 return GetOpndDes(1)->GetSize();
377 }
378 /* use dest operand */
379 return GetOpndDes(0)->GetSize();
380 }
381
Is64BitInsnDesc382 bool Is64Bit() const
383 {
384 return GetOperandSize() == k64BitSize;
385 }
386
IsValidImmOpndInsnDesc387 bool IsValidImmOpnd(int64 val) const
388 {
389 if (!validFunc) {
390 return true;
391 }
392 return validFunc(val);
393 }
394
GetLatencyTypeInsnDesc395 uint32 GetLatencyType() const
396 {
397 return latencyType;
398 }
399
IsUnaryOpInsnDesc400 bool IsUnaryOp() const
401 {
402 return (properties & ISUNARYOP) != 0;
403 }
404
IsShiftInsnDesc405 bool IsShift() const
406 {
407 return (properties & ISSHIFT) != 0;
408 }
409
GetNameInsnDesc410 const std::string &GetName() const
411 {
412 return name;
413 }
414
GetFormatInsnDesc415 const std::string &GetFormat() const
416 {
417 return format;
418 }
419
GetAtomicNumInsnDesc420 uint32 GetAtomicNum() const
421 {
422 return atomicNum;
423 }
424
GetEncodeTypeInsnDesc425 EncodeType GetEncodeType() const
426 {
427 return encodeType;
428 }
429
GetMopEncodeInsnDesc430 uint32 GetMopEncode() const
431 {
432 return mopEncode;
433 }
434
GetAbstractIdInsnDesc435 static const InsnDesc &GetAbstractId(MOperator opc)
436 {
437 DEBUG_ASSERT(opc < abstract::kMopLast, "op must be lower than kMopLast");
438 return abstractId[opc];
439 }
440
441 static const InsnDesc abstractId[abstract::kMopLast];
442 };
443
444 enum RegAddress : uint32 { kRegHigh = 0x4, kRegLow = 0x8 };
445 constexpr uint32 kMemLow12 = 0x10;
446 constexpr uint32 kLiteralLow12 = kMemLow12;
447 constexpr uint32 kPreInc = 0x20;
448 constexpr uint32 kPostInc = 0x40;
449 constexpr uint32 kLoadLiteral = 0x80;
450
451 enum BitIndex : maple::uint8 {
452 k8BitIndex = 0,
453 k16BitIndex,
454 k32BitIndex,
455 k64BitIndex,
456 kBitIndexEnd,
457 };
458
GetBitIndex(uint32 bitSize)459 static inline BitIndex GetBitIndex(uint32 bitSize)
460 {
461 switch (bitSize) {
462 case k8BitSize:
463 return k8BitIndex;
464 case k16BitSize:
465 return k16BitIndex;
466 case k32BitSize:
467 return k32BitIndex;
468 case k64BitSize:
469 return k64BitIndex;
470 default:
471 CHECK_FATAL(false, "NIY, Not support size");
472 }
473 }
474 } /* namespace maplebe */
475
476 #endif /* MAPLEBE_INCLUDE_CG_ISA_H */
477