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
142 enum MemoryOrdering : uint32 {
143 kMoNone = 0,
144 kMoAcquire = 1ULL, /* ARMv8 */
145 kMoAcquireRcpc = (1ULL << 1), /* ARMv8.3 */
146 kMoLoacquire = (1ULL << 2), /* ARMv8.1 */
147 kMoRelease = (1ULL << 3), /* ARMv8 */
148 kMoLorelease = (1ULL << 4) /* ARMv8.1 */
149 };
150
IsPseudoInstruction(MOperator mOp)151 static inline bool IsPseudoInstruction(MOperator mOp)
152 {
153 return (mOp >= MOP_pseudo_param_def_x && mOp <= MOP_pseudo_eh_def_x);
154 }
155
156 /*
157 * Precondition: The given insn is a jump instruction.
158 * Get the jump target label operand index from the given instruction.
159 * Note: MOP_xbr is a jump instruction, but the target is unknown at compile time,
160 * because a register instead of label. So we don't take it as a branching instruction.
161 * However for special long range branch patch, the label is installed in this case.
162 */
163 uint32 GetJumpTargetIdx(const Insn &insn);
164
165 bool IsSub(const Insn &insn);
166
167 MOperator GetMopSub2Subs(const Insn &insn);
168
169 MOperator FlipConditionOp(MOperator flippedOp);
170
171 // Function: for immediate verification, memopnd ofstvalue is returned from opnd input.
172 // It's worth noting that 0 will be returned when kBOR memopnd is input.
173 int64 GetMemOpndOffsetValue(Operand *o);
174
175 int32 GetTail0BitNum(int64 val);
176
177 int32 GetHead0BitNum(int64 val);
178
GetNextOffsetCalleeSaved(int & offset)179 inline void GetNextOffsetCalleeSaved(int &offset)
180 {
181 offset += (kAarch64IntregBytelen << 1);
182 }
183 } /* namespace AArch64isa */
184
185 /*
186 * We save callee-saved registers from lower stack area to upper stack area.
187 * If possible, we store a pair of registers (int/int and fp/fp) in the stack.
188 * The Stack Pointer has to be aligned at 16-byte boundary.
189 * On AArch64, kIntregBytelen == 8 (see the above)
190 */
191
192 MOperator GetMopPair(MOperator mop, bool isIncludeStrbStrh);
193 } /* namespace maplebe */
194
195 #endif /* MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_ISA_H */
196