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_AARCH64_AARCH64_ISA_H
17 #define MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_ISA_H
18
19 #include "isa.h"
20
21 #define DEFINE_MOP(op, ...) op,
22 enum AArch64MopT : maple::uint32 {
23 #include "abstract_mmir.def"
24 #include "aarch64_md.def"
25 kMopLast
26 };
27 #undef DEFINE_MOP
28
29 namespace maplebe {
30 /*
31 * ARM Architecture Reference Manual (for ARMv8)
32 * D1.8.2
33 */
34 constexpr int kAarch64StackPtrAlignment = 16;
35
36 constexpr int32 kAarch64OffsetAlign = 8;
37 constexpr uint32 kAarch64IntregBytelen = 8; /* 64-bit */
38 constexpr uint32 kAarch64FpregBytelen = 8; /* only lower 64 bits are used */
39 constexpr int kAarch64SizeOfFplr = 16;
40
41 enum StpLdpImmBound : int {
42 kStpLdpImm64LowerBound = -512,
43 kStpLdpImm64UpperBound = 504,
44 kStpLdpImm32LowerBound = -256,
45 kStpLdpImm32UpperBound = 252
46 };
47
48 enum StrLdrPerPostBound : int64 { kStrLdrPerPostLowerBound = -256, kStrLdrPerPostUpperBound = 255 };
49
50 constexpr int64 kStrAllLdrAllImmLowerBound = 0;
51 enum StrLdrImmUpperBound : int64 {
52 kStrLdrImm32UpperBound = 16380, /* must be a multiple of 4 */
53 kStrLdrImm64UpperBound = 32760, /* must be a multiple of 8 */
54 kStrbLdrbImmUpperBound = 4095,
55 kStrhLdrhImmUpperBound = 8190
56 };
57
58 /*
59 * ARM Compiler armasm User Guide version 6.6.
60 * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473j/deb1353594352617.html
61 * (retrieved on 3/24/2017)
62 *
63 * $ 4.1 Registers in AArch64 state
64 * ...When you use the 32-bit form of an instruction, the upper
65 * 32 bits of the source registers are ignored and
66 * the upper 32 bits of the destination register are set to zero.
67 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68 *
69 * There is no register named W31 or X31.
70 * Depending on the instruction, register 31 is either the stack
71 * pointer or the zero register. When used as the stack pointer,
72 * you refer to it as "SP". When used as the zero register, you refer
73 * to it as WZR in a 32-bit context or XZR in a 64-bit context.
74 * The zero register returns 0 when read and discards data when
75 * written (e.g., when setting the status register for testing).
76 */
77 enum AArch64reg : uint32 {
78 kRinvalid = kInvalidRegNO,
79 /* integer registers */
80 #define INT_REG(ID, PREF32, PREF64, canBeAssigned, isCalleeSave, isParam, isSpill, isExtraSpill) R##ID,
81 #define INT_REG_ALIAS(ALIAS, ID, PREF32, PREF64)
82 #include "aarch64_int_regs.def"
83 #undef INT_REG
84 #undef INT_REG_ALIAS
85 /* fp-simd registers */
86 #define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128, canBeAssigned, isCalleeSave, isParam, isSpill, isExtraSpill) V##ID,
87 #define FP_SIMD_REG_ALIAS(ID)
88 #include "aarch64_fp_simd_regs.def"
89 #undef FP_SIMD_REG
90 #undef FP_SIMD_REG_ALIAS
91 kMaxRegNum,
92 kRFLAG,
93 kAllRegNum,
94 /* alias */
95 #define INT_REG(ID, PREF32, PREF64, canBeAssigned, isCalleeSave, isParam, isSpill, isExtraSpill)
96 #define INT_REG_ALIAS(ALIAS, ID, PREF32, PREF64) R##ALIAS = R##ID,
97 #include "aarch64_int_regs.def"
98 #undef INT_REG
99 #undef INT_REG_ALIAS
100 #define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128, canBeAssigned, isCalleeSave, isParam, isSpill, isExtraSpill)
101 #define FP_SIMD_REG_ALIAS(ID) S##ID = V##ID,
102 #include "aarch64_fp_simd_regs.def"
103 #undef FP_SIMD_REG
104 #undef FP_SIMD_REG_ALIAS
105 #define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128, canBeAssigned, isCalleeSave, isParam, isSpill, isExtraSpill)
106 #define FP_SIMD_REG_ALIAS(ID) D##ID = V##ID,
107 #include "aarch64_fp_simd_regs.def"
108 #undef FP_SIMD_REG
109 #undef FP_SIMD_REG_ALIAS
110 };
111
112 class Insn;
113
114 namespace AArch64isa {
IsGPRegister(AArch64reg r)115 static inline bool IsGPRegister(AArch64reg r)
116 {
117 return R0 <= r && r <= RZR;
118 }
119
IsFPSIMDRegister(AArch64reg r)120 static inline bool IsFPSIMDRegister(AArch64reg r)
121 {
122 return V0 <= r && r <= V31;
123 }
124
IsPhysicalRegister(regno_t r)125 static inline bool IsPhysicalRegister(regno_t r)
126 {
127 return r < kMaxRegNum;
128 }
129
GetRegType(AArch64reg r)130 static inline RegType GetRegType(AArch64reg r)
131 {
132 if (IsGPRegister(r)) {
133 return kRegTyInt;
134 }
135 if (IsFPSIMDRegister(r)) {
136 return kRegTyFloat;
137 }
138 DEBUG_ASSERT(false, "No suitable register type to return?");
139 return kRegTyUndef;
140 }
141
IsPseudoInstruction(MOperator mOp)142 static inline bool IsPseudoInstruction(MOperator mOp)
143 {
144 return (mOp >= MOP_pseudo_param_def_x && mOp <= MOP_pseudo_eh_def_x);
145 }
146
147 /*
148 * Precondition: The given insn is a jump instruction.
149 * Get the jump target label operand index from the given instruction.
150 * Note: MOP_xbr is a jump instruction, but the target is unknown at compile time,
151 * because a register instead of label. So we don't take it as a branching instruction.
152 * However for special long range branch patch, the label is installed in this case.
153 */
154 uint32 GetJumpTargetIdx(const Insn &insn);
155
156 bool IsSub(const Insn &insn);
157
158 MOperator GetMopSub2Subs(const Insn &insn);
159
160 MOperator FlipConditionOp(MOperator flippedOp);
161
162 // Function: for immediate verification, memopnd ofstvalue is returned from opnd input.
163 // It's worth noting that 0 will be returned when kBOR memopnd is input.
164 int64 GetMemOpndOffsetValue(Operand *o);
165
166 int32 GetTail0BitNum(int64 val);
167
168 int32 GetHead0BitNum(int64 val);
169
GetNextOffsetCalleeSaved(int & offset)170 inline void GetNextOffsetCalleeSaved(int &offset)
171 {
172 offset += (kAarch64IntregBytelen << 1);
173 }
174 } /* namespace AArch64isa */
175
176 /*
177 * We save callee-saved registers from lower stack area to upper stack area.
178 * If possible, we store a pair of registers (int/int and fp/fp) in the stack.
179 * The Stack Pointer has to be aligned at 16-byte boundary.
180 * On AArch64, kIntregBytelen == 8 (see the above)
181 */
182
183 MOperator GetMopPair(MOperator mop, bool isIncludeStrbStrh);
184 } /* namespace maplebe */
185
186 #endif /* MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_ISA_H */
187