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 #include "aarch64_cg.h"
17 #include <cinttypes>
18 #include "aarch64_mop_split.h"
19 #include "aarch64_mop_valid.h"
20 #include "mir_builder.h"
21 #include "becommon.h"
22 #include "label_creation.h"
23 #include "alignment.h"
24 #include "operand.h"
25
26 namespace maplebe {
27 #define DEFINE_MOP(...) {__VA_ARGS__},
28 const InsnDesc AArch64CG::kMd[kMopLast] = {
29 #include "abstract_mmir.def"
30 #include "aarch64_md.def"
31 };
32 #undef DEFINE_MOP
33
34 std::array<std::array<const std::string, kAllRegNum>, kIntRegTypeNum> AArch64CG::intRegNames = {
35 std::array<const std::string, kAllRegNum> {
36 "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7",
37 "err8", "err9", "err10", "err11", "err12", "err13", "err14", "err15", "err16",
38 "err17", "err18", "err19", "err20", "err21", "err22", "err23", "err24", "err25",
39 "err26", "err27", "err28", "err", "err", "err", "errsp", "errzr", /* x29 is fp */
40 "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8",
41 "b9", "b10", "b11", "b12", "b13", "b14", "b15", "b16", "b17",
42 "b18", "b19", "b20", "b21", "b22", "b23", "b24", "b25", "b26",
43 "b27", "b28", "b29", "b30", "b31", "errMaxRegNum", "rflag"},
44 std::array<const std::string, kAllRegNum> {
45 "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7",
46 "err8", "err9", "err10", "err11", "err12", "err13", "err14", "err15", "err16",
47 "err17", "err18", "err19", "err20", "err21", "err22", "err23", "err24", "err25",
48 "err26", "err27", "err28", "err29", "err30", "err31", "errsp", "errzr", /* x29 is fp */
49 "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8",
50 "h9", "h10", "h11", "h12", "h13", "h14", "h15", "h16", "h17",
51 "h18", "h19", "h20", "h21", "h22", "h23", "h24", "h25", "h26",
52 "h27", "h28", "h29", "h30", "h31", "errMaxRegNum", "rflag"},
53 std::array<const std::string, kAllRegNum> {
54 "err", "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10",
55 "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22",
56 "w23", "w24", "w25", "w26", "w27", "w28", "w29", "err", "err", "wsp", "wzr", /* x29 is fp */
57 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
58 "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
59 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", "errMaxRegNum", "rflag"},
60 std::array<const std::string, kAllRegNum> {
61 "err", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9",
62 "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20",
63 "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x29" /* use X40 when debug */,
64 "sp", "xzr", /* x29 is fp */
65 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
66 "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21",
67 "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "errMaxRegNum",
68 "rflag"},
69 std::array<const std::string, kAllRegNum> {
70 "err", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9",
71 "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20",
72 "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x29" /* use X40 when debug */,
73 "sp", "xzr", /* x29 is fp */
74 "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10",
75 "q11", "q12", "q13", "q14", "q15", "q16", "q17", "q18", "q19", "q20", "q21",
76 "q22", "q23", "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31", "errMaxRegNum",
77 "rflag"}};
78
79 std::array<const std::string, kAllRegNum> AArch64CG::vectorRegNames = {
80 "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7", "err8", "err9", "err10", "err11", "err12",
81 "err13", "err14", "err15", "err16", "err17", "err18", "err19", "err20", "err21", "err22",
82 /* x29 is fp, err40 is fp before RA */
83 "err23", "err24", "err25", "err26", "err27", "err28", "err29", "err30", "errsp", "errzr", "err40", "v0", "v1", "v2",
84 "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
85 "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "errMaxRegNum", "rflag"};
86
IsExclusiveFunc(MIRFunction & mirFunc)87 bool AArch64CG::IsExclusiveFunc(MIRFunction &mirFunc)
88 {
89 const std::string &funcName = mirFunc.GetName();
90 for (const auto &it : ehExclusiveNameVec) {
91 if (it.compare(funcName) == 0) {
92 return true;
93 }
94 }
95 return false;
96 }
97 namespace wordsMap {
98 /*
99 * Generate object maps.
100 *
101 * 1. each class record its GCTIB in method meta (not read only meta)
102 * 2. GCTIB include: header protoType; n bitmap word; bitmap word
103 * 3. each reference word(4 or 8 bytes) is represented by 2 bits
104 * 00: not ref
105 * 01: normal ref
106 * 10: weak ref
107 * 11: unowned ref
108 *
109 * For example, if a scalar object has five ptr fields at offsets 24, 40(weak),
110 * 64(unowned), the generated code will be like:
111 *
112 * MCC_GCTIB__xxx:
113 * .long 0x40 // object has child reference
114 * .long 1 // one word in the bitmap
115 * .quad 0b110000100001000000
116 * ...
117 */
118 const uint32 kRefWordsPerMapWord = 32; /* contains bitmap for 32 ref words in 64 bits */
119 const uint32 kLogRefWordsPerMapWord = 5;
120 #ifdef USE_32BIT_REF
121 const uint32 kReferenceWordSize = 4;
122 const uint32 kLog2ReferenceWordSize = 2;
123 #else
124 const uint32 kReferenceWordSize = 8;
125 const uint32 kLog2ReferenceWordSize = 3;
126 #endif
127 const uint32 kInMapWordOffsetMask = ((kReferenceWordSize * kRefWordsPerMapWord) - 1);
128 const uint32 kInMapWordIndexShift = (kLog2ReferenceWordSize - 1);
129 const uint32 kMapWordIndexShift = (kLog2ReferenceWordSize + kLogRefWordsPerMapWord);
130
131 const uint64 kRefBits = 1;
132 const uint64 kWeakRefBits = 2;
133 const uint64 kUnownedRefBits = 3;
134
135 /*
136 * Give a structrue type, calculate its bitmap_vector
137 */
GetGCTIBBitMapWords(const BECommon & beCommon,MIRStructType & stType,std::vector<uint64> & bitmapWords)138 static void GetGCTIBBitMapWords(const BECommon &beCommon, MIRStructType &stType, std::vector<uint64> &bitmapWords)
139 {
140 bitmapWords.clear();
141 if (stType.GetKind() == kTypeClass) {
142 uint64 curBitmap = 0;
143 uint32 curBitmapIndex = 0;
144 uint32 prevOffset = 0;
145 for (const auto &fieldInfo : beCommon.GetJClassLayout(static_cast<MIRClassType &>(stType))) {
146 if (fieldInfo.IsRef()) {
147 uint32 curOffset = fieldInfo.GetOffset();
148 /* skip meta field */
149 if (curOffset == 0) {
150 continue;
151 }
152 CHECK_FATAL((curOffset > prevOffset) || (prevOffset == 0), "not ascending offset");
153 uint32 wordIndex = curOffset >> kMapWordIndexShift;
154 if (wordIndex > curBitmapIndex) {
155 bitmapWords.emplace_back(curBitmap);
156 for (uint32 i = curBitmapIndex + 1; i < wordIndex; i++) {
157 bitmapWords.emplace_back(0);
158 }
159 curBitmap = 0;
160 curBitmapIndex = wordIndex;
161 }
162 uint32 bitOffset = (curOffset & kInMapWordOffsetMask) >> kInMapWordIndexShift;
163 if (CGOptions::IsGCOnly()) {
164 /* ignore unowned/weak when GCONLY is enabled. */
165 curBitmap |= (kRefBits << bitOffset);
166 } else if (fieldInfo.IsUnowned()) {
167 curBitmap |= (kUnownedRefBits << bitOffset);
168 } else if (fieldInfo.IsWeak()) {
169 curBitmap |= (kWeakRefBits << bitOffset);
170 } else {
171 /* ref */
172 curBitmap |= (kRefBits << bitOffset);
173 }
174 prevOffset = curOffset;
175 }
176 }
177 if (curBitmap != 0) {
178 bitmapWords.emplace_back(curBitmap);
179 }
180 } else if (stType.GetKind() != kTypeInterface) {
181 /* interface doesn't have reference fields */
182 CHECK_FATAL(false, "GetGCTIBBitMapWords unexpected type");
183 }
184 }
185 } // namespace wordsMap
186
IsTargetInsn(MOperator mOp) const187 bool AArch64CG::IsTargetInsn(MOperator mOp) const
188 {
189 return (mOp > MOP_undef && mOp <= MOP_nop);
190 }
IsClinitInsn(MOperator mOp) const191 bool AArch64CG::IsClinitInsn(MOperator mOp) const
192 {
193 return (mOp == MOP_clinit || mOp == MOP_clinit_tail || mOp == MOP_adrp_ldr);
194 }
IsPseudoInsn(MOperator mOp) const195 bool AArch64CG::IsPseudoInsn(MOperator mOp) const
196 {
197 return (mOp >= MOP_pseudo_param_def_x && mOp < MOP_nop);
198 }
199
IsEffectiveCopy(Insn & insn) const200 bool AArch64CG::IsEffectiveCopy(Insn &insn) const
201 {
202 MOperator mOp = insn.GetMachineOpcode();
203 if (mOp >= MOP_xmovrr && mOp <= MOP_xvmovrv) {
204 return true;
205 }
206 if (mOp == MOP_vmovuu || mOp == MOP_vmovvv) {
207 return true;
208 }
209 if ((mOp >= MOP_xaddrrr && mOp <= MOP_ssub) || (mOp >= MOP_xlslrri6 && mOp <= MOP_wlsrrrr)) {
210 Operand &opnd2 = insn.GetOperand(kInsnThirdOpnd);
211 if (opnd2.IsIntImmediate()) {
212 auto &immOpnd = static_cast<ImmOperand &>(opnd2);
213 if (immOpnd.IsZero()) {
214 return true;
215 }
216 }
217 }
218 if (mOp > MOP_xmulrrr && mOp <= MOP_xvmuld) {
219 Operand &opnd2 = insn.GetOperand(kInsnThirdOpnd);
220 if (opnd2.IsIntImmediate()) {
221 auto &immOpnd = static_cast<ImmOperand &>(opnd2);
222 if (immOpnd.GetValue() == 1) {
223 return true;
224 }
225 }
226 }
227 return false;
228 }
229
DumpTargetOperand(Operand & opnd,const OpndDesc & opndDesc) const230 void AArch64CG::DumpTargetOperand(Operand &opnd, const OpndDesc &opndDesc) const
231 {
232 A64OpndDumpVisitor visitor(opndDesc);
233 opnd.Accept(visitor);
234 }
235
EmitGCTIBLabel(GCTIBKey * key,const std::string & gcTIBName,std::vector<uint64> & bitmapWords,uint32 rcHeader)236 void AArch64CG::EmitGCTIBLabel(GCTIBKey *key, const std::string &gcTIBName,
237 std::vector<uint64> &bitmapWords, uint32 rcHeader)
238 {
239 GCTIBPattern *ptn = memPool->New<GCTIBPattern>(*key, *memPool);
240 (void)keyPatternMap.insert(std::make_pair(key, ptn));
241 (void)symbolPatternMap.insert(std::make_pair(gcTIBName, ptn));
242
243 /* Emit GCTIB pattern */
244 std::string ptnString = "\t.type " + ptn->GetName() + ", %object\n" + "\t.data\n" + "\t.align 3\n";
245 MIRSymbol *gcTIBSymbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(
246 GlobalTables::GetStrTable().GetStrIdxFromName(gcTIBName));
247 if (gcTIBSymbol != nullptr && gcTIBSymbol->GetStorageClass() == kScFstatic) {
248 ptnString += "\t.local ";
249 } else {
250 ptnString += "\t.global ";
251 }
252
253 Emit([&ptnString, ptn, rcHeader, &bitmapWords](Emitter *emitter) {
254 emitter->Emit(ptnString);
255 emitter->Emit(ptn->GetName());
256 emitter->Emit("\n");
257
258 /* Emit the GCTIB pattern label for the class */
259 emitter->Emit(ptn->GetName());
260 emitter->Emit(":\n");
261
262 emitter->Emit("\t.long ");
263 emitter->EmitHexUnsigned(rcHeader);
264 emitter->Emit("\n");
265
266 /* generate n_bitmap word */
267 emitter->Emit("\t.long "); /* AArch64-specific. Generate a 64-bit value. */
268 emitter->EmitDecUnsigned(bitmapWords.size());
269 emitter->Emit("\n");
270
271 /* Emit each bitmap word */
272 for (const auto &bitmapWord : bitmapWords) {
273 if (!CGOptions::IsQuiet()) {
274 LogInfo::MapleLogger() << " bitmap_word: 0x" << bitmapWord << " " << PRIx64 << "\n";
275 }
276 emitter->Emit("\t.quad "); /* AArch64-specific. Generate a 64-bit value. */
277 emitter->EmitHexUnsigned(bitmapWord);
278 emitter->Emit("\n");
279 }
280 });
281 if (gcTIBSymbol != nullptr && gcTIBSymbol->GetStorageClass() != kScFstatic) {
282 /* add local symbol REF_XXX to every global GCTIB symbol */
283 CreateRefSymForGlobalPtn(*ptn);
284 keyPatternMap[key] = ptn;
285 }
286 }
287
288 /*
289 * Find if there exist same GCTIB (both rcheader and bitmap are same)
290 * for different class. If ture reuse, if not emit and record new GCTIB.
291 */
FindOrCreateRepresentiveSym(std::vector<uint64> & bitmapWords,uint32 rcHeader,const std::string & name)292 void AArch64CG::FindOrCreateRepresentiveSym(std::vector<uint64> &bitmapWords, uint32 rcHeader, const std::string &name)
293 {
294 GCTIBKey *key = memPool->New<GCTIBKey>(allocator, rcHeader, bitmapWords);
295 const std::string &gcTIBName = GCTIB_PREFIX_STR + name;
296 MapleUnorderedMap<GCTIBKey *, GCTIBPattern *, Hasher, EqualFn>::const_iterator iter = keyPatternMap.find(key);
297 if (iter == keyPatternMap.end()) {
298 /* Emit the GCTIB label for the class */
299 EmitGCTIBLabel(key, gcTIBName, bitmapWords, rcHeader);
300 } else {
301 (void)symbolPatternMap.insert(make_pair(gcTIBName, iter->second));
302 }
303 }
304
305 /*
306 * Add local symbol REF_XXX to global GCTIB symbol,
307 * and replace the global GCTIBPattern in keyPatternMap.
308 */
CreateRefSymForGlobalPtn(GCTIBPattern & ptn) const309 void AArch64CG::CreateRefSymForGlobalPtn(GCTIBPattern &ptn) const
310 {
311 const std::string &refPtnString = REF_PREFIX_STR + ptn.GetName();
312 const std::string &ptnString = "\t.type " + refPtnString + ", %object\n" + "\t.data\n" + "\t.align 3\n" +
313 "\t.local " + refPtnString + "\n" + refPtnString + ":\n" + "\t.quad " +
314 ptn.GetName() + "\n";
315 Emit([&ptnString](Emitter *emitter) {
316 emitter->Emit(ptnString);
317 });
318 ptn.SetName(refPtnString);
319 }
320
FindGCTIBPatternName(const std::string & name) const321 std::string AArch64CG::FindGCTIBPatternName(const std::string &name) const
322 {
323 auto iter = symbolPatternMap.find(name);
324 if (iter == symbolPatternMap.end()) {
325 CHECK_FATAL(false, "No GCTIB pattern found for symbol: %s", name.c_str());
326 }
327 return iter->second->GetName();
328 }
329
GenerateObjectMaps(BECommon & beCommon)330 void AArch64CG::GenerateObjectMaps(BECommon &beCommon)
331 {
332 if (!CGOptions::IsQuiet()) {
333 LogInfo::MapleLogger() << "DEBUG: Generating object maps...\n";
334 }
335
336 for (auto &tyId : GetMIRModule()->GetClassList()) {
337 if (!CGOptions::IsQuiet()) {
338 LogInfo::MapleLogger() << "Class tyIdx: " << tyId << "\n";
339 }
340 TyIdx tyIdx(tyId);
341 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
342 DEBUG_ASSERT(ty != nullptr, "ty nullptr check");
343 /* Only emit GCTIB for classes owned by this module */
344 DEBUG_ASSERT(ty->IsStructType(), "ty isn't MIRStructType* in AArch64CG::GenerateObjectMaps");
345 MIRStructType *strTy = static_cast<MIRStructType *>(ty);
346 if (!strTy->IsLocal()) {
347 continue;
348 }
349
350 GStrIdx nameIdx = ty->GetNameStrIdx();
351
352 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx);
353
354 /* Emit for a class */
355 if (!CGOptions::IsQuiet()) {
356 LogInfo::MapleLogger() << " name: " << name << "\n";
357 }
358
359 std::vector<uint64> bitmapWords;
360 wordsMap::GetGCTIBBitMapWords(beCommon, *strTy, bitmapWords);
361 /* fill specific header according to the size of bitmapWords */
362 uint32 rcHeader = (!bitmapWords.empty()) ? 0x40 : 0;
363 FindOrCreateRepresentiveSym(bitmapWords, rcHeader, name);
364 }
365 }
366
EnrollTargetPhases(MaplePhaseManager * pm) const367 void AArch64CG::EnrollTargetPhases(MaplePhaseManager *pm) const
368 {
369 if (!GetMIRModule()->IsCModule()) {
370 CGOptions::DisableCGSSA();
371 }
372 #include "aarch64_phases.def"
373 }
374
BuildPhiInsn(RegOperand & defOpnd,Operand & listParam)375 Insn &AArch64CG::BuildPhiInsn(RegOperand &defOpnd, Operand &listParam)
376 {
377 DEBUG_ASSERT(defOpnd.IsRegister(), "build SSA on register operand");
378 /* There are cases that CCRegs need add phi insn. */
379 CHECK_FATAL(defOpnd.IsOfIntClass() || defOpnd.IsOfFloatOrSIMDClass() || defOpnd.IsOfCC(), " unknown operand type ");
380 bool is64bit = defOpnd.GetSize() == k64BitSize;
381 MOperator mop = MOP_nop;
382 if (defOpnd.GetSize() == k128BitSize) {
383 DEBUG_ASSERT(defOpnd.IsOfFloatOrSIMDClass(), "unexpect 128bit int operand in aarch64");
384 mop = MOP_xvphivd;
385 } else {
386 mop = defOpnd.IsOfIntClass() ? is64bit ? MOP_xphirr : MOP_wphirr : is64bit ? MOP_xvphid : MOP_xvphis;
387 }
388 DEBUG_ASSERT(mop != MOP_nop, "unexpect 128bit int operand in aarch64");
389 return GetCurCGFuncNoConst()->GetInsnBuilder()->BuildInsn(mop, defOpnd, listParam);
390 }
391
CreatePhiOperand(MemPool & mp,MapleAllocator & mAllocator)392 PhiOperand &AArch64CG::CreatePhiOperand(MemPool &mp, MapleAllocator &mAllocator)
393 {
394 return *mp.New<PhiOperand>(mAllocator);
395 }
396 } /* namespace maplebe */
397