• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "aarch64_cgfunc.h"
18 #include <vector>
19 #include <cstdint>
20 #include <sys/stat.h>
21 #include <atomic>
22 #include "cfi.h"
23 #include "mpl_logging.h"
24 #include "rt.h"
25 #include "opcode_info.h"
26 #include "mir_builder.h"
27 #include "mir_symbol_builder.h"
28 #include "mpl_atomic.h"
29 #include "metadata_layout.h"
30 #include "emit.h"
31 #include "simplify.h"
32 #include <algorithm>
33 
34 namespace maplebe {
35 using namespace maple;
36 CondOperand AArch64CGFunc::ccOperands[kCcLast] = {
37     CondOperand(CC_EQ), CondOperand(CC_NE), CondOperand(CC_CS), CondOperand(CC_HS), CondOperand(CC_CC),
38     CondOperand(CC_LO), CondOperand(CC_MI), CondOperand(CC_PL), CondOperand(CC_VS), CondOperand(CC_VC),
39     CondOperand(CC_HI), CondOperand(CC_LS), CondOperand(CC_GE), CondOperand(CC_LT), CondOperand(CC_GT),
40     CondOperand(CC_LE), CondOperand(CC_AL),
41 };
42 
43 namespace {
44 constexpr int32 kSignedDimension = 2;        /* signed and unsigned */
45 constexpr int32 kIntByteSizeDimension = 4;   /* 1 byte, 2 byte, 4 bytes, 8 bytes */
46 constexpr int32 kFloatByteSizeDimension = 3; /* 4 bytes, 8 bytes, 16 bytes(vector) */
47 constexpr int32 kShiftAmount12 = 12;         /* for instruction that can use shift, shift amount must be 0 or 12 */
48 
49 MOperator ldIs[kSignedDimension][kIntByteSizeDimension] = {
50     /* unsigned == 0 */
51     {MOP_wldrb, MOP_wldrh, MOP_wldr, MOP_xldr},
52     /* signed == 1 */
53     {MOP_wldrsb, MOP_wldrsh, MOP_wldr, MOP_xldr}};
54 
55 MOperator stIs[kSignedDimension][kIntByteSizeDimension] = {
56     /* unsigned == 0 */
57     {MOP_wstrb, MOP_wstrh, MOP_wstr, MOP_xstr},
58     /* signed == 1 */
59     {MOP_wstrb, MOP_wstrh, MOP_wstr, MOP_xstr}};
60 
61 MOperator ldIsAcq[kSignedDimension][kIntByteSizeDimension] = {
62     /* unsigned == 0 */
63     {MOP_wldarb, MOP_wldarh, MOP_wldar, MOP_xldar},
64     /* signed == 1 */
65     {MOP_wldarb, MOP_wldarh, MOP_wldar, MOP_xldar}};
66 
67 MOperator stIsRel[kSignedDimension][kIntByteSizeDimension] = {
68     /* unsigned == 0 */
69     {MOP_wstlrb, MOP_wstlrh, MOP_wstlr, MOP_xstlr},
70     /* signed == 1 */
71     {MOP_wstlrb, MOP_wstlrh, MOP_wstlr, MOP_xstlr}};
72 
73 MOperator ldFs[kFloatByteSizeDimension] = {MOP_sldr, MOP_dldr, MOP_qldr};
74 MOperator stFs[kFloatByteSizeDimension] = {MOP_sstr, MOP_dstr, MOP_qstr};
75 
76 MOperator ldFsAcq[kFloatByteSizeDimension] = {MOP_undef, MOP_undef, MOP_undef};
77 MOperator stFsRel[kFloatByteSizeDimension] = {MOP_undef, MOP_undef, MOP_undef};
78 
79 /* extended to unsigned ints */
80 MOperator uextIs[kIntByteSizeDimension][kIntByteSizeDimension] = {
81     /*  u8         u16          u32          u64      */
82     {MOP_undef, MOP_xuxtb32, MOP_xuxtb32, MOP_xuxtb32}, /* u8/i8   */
83     {MOP_undef, MOP_undef, MOP_xuxth32, MOP_xuxth32},   /* u16/i16 */
84     {MOP_undef, MOP_undef, MOP_xuxtw64, MOP_xuxtw64},   /* u32/i32 */
85     {MOP_undef, MOP_undef, MOP_undef, MOP_undef}        /* u64/u64 */
86 };
87 
88 /* extended to signed ints */
89 MOperator extIs[kIntByteSizeDimension][kIntByteSizeDimension] = {
90     /*  i8         i16          i32          i64      */
91     {MOP_undef, MOP_xsxtb32, MOP_xsxtb32, MOP_xsxtb64}, /* u8/i8   */
92     {MOP_undef, MOP_undef, MOP_xsxth32, MOP_xsxth64},   /* u16/i16 */
93     {MOP_undef, MOP_undef, MOP_undef, MOP_xsxtw64},     /* u32/i32 */
94     {MOP_undef, MOP_undef, MOP_undef, MOP_undef}        /* u64/u64 */
95 };
96 
PickLdStInsn(bool isLoad,uint32 bitSize,PrimType primType,AArch64isa::MemoryOrdering memOrd)97 MOperator PickLdStInsn(bool isLoad, uint32 bitSize, PrimType primType, AArch64isa::MemoryOrdering memOrd)
98 {
99     DEBUG_ASSERT(__builtin_popcount(static_cast<uint32>(memOrd)) <= 1, "must be kMoNone or kMoAcquire");
100     DEBUG_ASSERT(bitSize >= k8BitSize, "PTY_u1 should have been lowered?");
101     DEBUG_ASSERT(__builtin_popcount(bitSize) == 1, "PTY_u1 should have been lowered?");
102     if (isLoad) {
103         DEBUG_ASSERT((memOrd == AArch64isa::kMoNone) || (memOrd == AArch64isa::kMoAcquire) ||
104                          (memOrd == AArch64isa::kMoAcquireRcpc) || (memOrd == AArch64isa::kMoLoacquire),
105                      "unknown Memory Order");
106     } else {
107         DEBUG_ASSERT((memOrd == AArch64isa::kMoNone) || (memOrd == AArch64isa::kMoRelease) ||
108                          (memOrd == AArch64isa::kMoLorelease),
109                      "unknown Memory Order");
110     }
111 
112     /* __builtin_ffs(x) returns: 0 -> 0, 1 -> 1, 2 -> 2, 4 -> 3, 8 -> 4 */
113     if ((IsPrimitiveInteger(primType) || primType == PTY_agg) && !IsPrimitiveVector(primType)) {
114         MOperator(*table)[kIntByteSizeDimension];
115         if (isLoad) {
116             table = (memOrd == AArch64isa::kMoAcquire) ? ldIsAcq : ldIs;
117         } else {
118             table = (memOrd == AArch64isa::kMoRelease) ? stIsRel : stIs;
119         }
120 
121         int32 signedUnsigned = IsUnsignedInteger(primType) ? 0 : 1;
122         if (primType == PTY_agg) {
123             CHECK_FATAL(bitSize >= k8BitSize, " unexpect agg size");
124             bitSize = static_cast<uint32>(RoundUp(bitSize, k8BitSize));
125             DEBUG_ASSERT((bitSize & (bitSize - 1)) == 0, "bitlen error");
126         }
127 
128         /* __builtin_ffs(x) returns: 8 -> 4, 16 -> 5, 32 -> 6, 64 -> 7 */
129         if (primType == PTY_i128 || primType == PTY_u128) {
130             bitSize = k64BitSize;
131         }
132         uint32 size = static_cast<uint32>(__builtin_ffs(static_cast<int32>(bitSize))) - k4BitSize;
133         DEBUG_ASSERT(size <= 3, "wrong bitSize");  // size must <= 3
134         return table[signedUnsigned][size];
135     } else {
136         MOperator *table = nullptr;
137         if (isLoad) {
138             table = (memOrd == AArch64isa::kMoAcquire) ? ldFsAcq : ldFs;
139         } else {
140             table = (memOrd == AArch64isa::kMoRelease) ? stFsRel : stFs;
141         }
142 
143         /* __builtin_ffs(x) returns: 32 -> 6, 64 -> 7, 128 -> 8 */
144         uint32 size = static_cast<uint32>(__builtin_ffs(static_cast<int32>(bitSize))) - k6BitSize;
145         DEBUG_ASSERT(size <= k2BitSize, "size must be 0 to 2");
146         return table[size];
147     }
148 }
149 }  // namespace
150 
IsBlkassignForPush(const BlkassignoffNode & bNode)151 bool IsBlkassignForPush(const BlkassignoffNode &bNode)
152 {
153     BaseNode *dest = bNode.Opnd(0);
154     bool spBased = false;
155     if (dest->GetOpCode() == OP_regread) {
156         RegreadNode &node = static_cast<RegreadNode &>(*dest);
157         if (-node.GetRegIdx() == kSregSp) {
158             spBased = true;
159         }
160     }
161     return spBased;
162 }
163 
SetMemReferenceOfInsn(Insn & insn,BaseNode * baseNode)164 void AArch64CGFunc::SetMemReferenceOfInsn(Insn &insn, BaseNode *baseNode)
165 {
166     if (baseNode == nullptr) {
167         return;
168     }
169     MIRFunction &mirFunction = GetFunction();
170     MemReferenceTable *memRefTable = mirFunction.GetMemReferenceTable();
171     // In O0 mode, we do not run the ME, and the referenceTable is nullptr
172     if (memRefTable == nullptr) {
173         return;
174     }
175     MemDefUsePart &memDefUsePart = memRefTable->GetMemDefUsePart();
176     if (memDefUsePart.find(baseNode) != memDefUsePart.end()) {
177         insn.SetReferenceOsts(memDefUsePart.find(baseNode)->second);
178     }
179 }
180 
GetLmbcStructArgType(BaseNode & stmt,size_t argNo) const181 MIRStructType *AArch64CGFunc::GetLmbcStructArgType(BaseNode &stmt, size_t argNo) const
182 {
183     MIRType *ty = nullptr;
184     if (stmt.GetOpCode() == OP_call) {
185         CallNode &callNode = static_cast<CallNode &>(stmt);
186         MIRFunction *callFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx());
187         if (callFunc->GetFormalCount() < (argNo + 1UL)) {
188             return nullptr; /* formals less than actuals */
189         }
190         ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callFunc->GetFormalDefVec()[argNo].formalTyIdx);
191     } else if (stmt.GetOpCode() == OP_icallproto) {
192         argNo--; /* 1st opnd of icallproto is funcname, skip it relative to param list */
193         IcallNode &icallproto = static_cast<IcallNode &>(stmt);
194         MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(icallproto.GetRetTyIdx());
195         MIRFuncType *fType = nullptr;
196         if (type->IsMIRPtrType()) {
197             fType = static_cast<MIRPtrType *>(type)->GetPointedFuncType();
198         } else {
199             fType = static_cast<MIRFuncType *>(type);
200         }
201         CHECK_FATAL(fType != nullptr, "invalid fType");
202         if (fType->GetParamTypeList().size() < (argNo + 1UL)) {
203             return nullptr;
204         }
205         ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fType->GetNthParamType(argNo));
206     }
207     CHECK_FATAL(ty && ty->IsStructType(), "lmbc agg arg error");
208     return static_cast<MIRStructType *>(ty);
209 }
210 
GetOrCreateResOperand(const BaseNode & parent,PrimType primType)211 RegOperand &AArch64CGFunc::GetOrCreateResOperand(const BaseNode &parent, PrimType primType)
212 {
213     RegOperand *resOpnd = nullptr;
214     if (parent.GetOpCode() == OP_regassign) {
215         auto &regAssignNode = static_cast<const RegassignNode &>(parent);
216         PregIdx pregIdx = regAssignNode.GetRegIdx();
217         if (IsSpecialPseudoRegister(pregIdx)) {
218             /* if it is one of special registers */
219             resOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, primType);
220         } else {
221             resOpnd = &GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
222         }
223     } else {
224         resOpnd = &CreateRegisterOperandOfType(primType);
225     }
226     return *resOpnd;
227 }
228 
PickLdInsn(uint32 bitSize,PrimType primType,AArch64isa::MemoryOrdering memOrd) const229 MOperator AArch64CGFunc::PickLdInsn(uint32 bitSize, PrimType primType, AArch64isa::MemoryOrdering memOrd) const
230 {
231     return PickLdStInsn(true, bitSize, primType, memOrd);
232 }
233 
PickStInsn(uint32 bitSize,PrimType primType,AArch64isa::MemoryOrdering memOrd) const234 MOperator AArch64CGFunc::PickStInsn(uint32 bitSize, PrimType primType, AArch64isa::MemoryOrdering memOrd) const
235 {
236     return PickLdStInsn(false, bitSize, primType, memOrd);
237 }
238 
PickExtInsn(PrimType dtype,PrimType stype) const239 MOperator AArch64CGFunc::PickExtInsn(PrimType dtype, PrimType stype) const
240 {
241     int32 sBitSize = static_cast<int32>(GetPrimTypeBitSize(stype));
242     int32 dBitSize = static_cast<int32>(GetPrimTypeBitSize(dtype));
243     /* __builtin_ffs(x) returns: 0 -> 0, 1 -> 1, 2 -> 2, 4 -> 3, 8 -> 4 */
244     if (IsPrimitiveInteger(stype) && IsPrimitiveInteger(dtype)) {
245         MOperator(*table)[kIntByteSizeDimension];
246         table = IsUnsignedInteger(stype) ? uextIs : extIs;
247         if (stype == PTY_i128 || stype == PTY_u128) {
248             sBitSize = static_cast<int32>(k64BitSize);
249         }
250         /* __builtin_ffs(x) returns: 8 -> 4, 16 -> 5, 32 -> 6, 64 -> 7 */
251         uint32 row = static_cast<uint32>(__builtin_ffs(sBitSize)) - k4BitSize;
252         DEBUG_ASSERT(row <= k3BitSize, "wrong bitSize");
253         if (dtype == PTY_i128 || dtype == PTY_u128) {
254             dBitSize = static_cast<int32>(k64BitSize);
255         }
256         uint32 col = static_cast<uint32>(__builtin_ffs(dBitSize)) - k4BitSize;
257         DEBUG_ASSERT(col <= k3BitSize, "wrong bitSize");
258         return table[row][col];
259     }
260     CHECK_FATAL(0, "extend not primitive integer");
261     return MOP_undef;
262 }
263 
PickMovBetweenRegs(PrimType destType,PrimType srcType) const264 MOperator AArch64CGFunc::PickMovBetweenRegs(PrimType destType, PrimType srcType) const
265 {
266     if (IsPrimitiveVector(destType) && IsPrimitiveVector(srcType)) {
267         return GetPrimTypeSize(srcType) == k8ByteSize ? MOP_vmovuu : MOP_vmovvv;
268     }
269     if (IsPrimitiveInteger(destType) && IsPrimitiveInteger(srcType)) {
270         return GetPrimTypeSize(srcType) <= k4ByteSize ? MOP_wmovrr : MOP_xmovrr;
271     }
272     if (IsPrimitiveFloat(destType) && IsPrimitiveFloat(srcType)) {
273         return GetPrimTypeSize(srcType) <= k4ByteSize ? MOP_xvmovs : MOP_xvmovd;
274     }
275     if (IsPrimitiveInteger(destType) && IsPrimitiveFloat(srcType)) {
276         return GetPrimTypeSize(srcType) <= k4ByteSize ? MOP_xvmovrs : MOP_xvmovrd;
277     }
278     if (IsPrimitiveFloat(destType) && IsPrimitiveInteger(srcType)) {
279         return GetPrimTypeSize(srcType) <= k4ByteSize ? MOP_xvmovsr : MOP_xvmovdr;
280     }
281     if (IsPrimitiveInteger(destType) && IsPrimitiveVector(srcType)) {
282         return GetPrimTypeSize(srcType) == k8ByteSize
283                    ? MOP_vwmovru
284                    : GetPrimTypeSize(destType) <= k4ByteSize ? MOP_vwmovrv : MOP_vxmovrv;
285     }
286     CHECK_FATAL(false, "unexpected operand primtype for mov");
287     return MOP_undef;
288 }
289 
PickMovInsn(const RegOperand & lhs,const RegOperand & rhs) const290 MOperator AArch64CGFunc::PickMovInsn(const RegOperand &lhs, const RegOperand &rhs) const
291 {
292     CHECK_FATAL(lhs.GetRegisterType() == rhs.GetRegisterType(), "PickMovInsn: unequal kind NYI");
293     CHECK_FATAL(lhs.GetSize() == rhs.GetSize(), "PickMovInsn: unequal size NYI");
294     DEBUG_ASSERT(((lhs.GetSize() < k64BitSize) || (lhs.GetRegisterType() == kRegTyFloat)),
295                  "should split the 64 bits or more mov");
296     if (lhs.GetRegisterType() == kRegTyInt) {
297         return MOP_wmovrr;
298     }
299     if (lhs.GetRegisterType() == kRegTyFloat) {
300         return (lhs.GetSize() <= k32BitSize) ? MOP_xvmovs : MOP_xvmovd;
301     }
302     DEBUG_ASSERT(false, "PickMovInsn: kind NYI");
303     return MOP_undef;
304 }
305 
SelectLoadAcquire(Operand & dest,PrimType dtype,Operand & src,PrimType stype,AArch64isa::MemoryOrdering memOrd,bool isDirect)306 void AArch64CGFunc::SelectLoadAcquire(Operand &dest, PrimType dtype, Operand &src, PrimType stype,
307                                       AArch64isa::MemoryOrdering memOrd, bool isDirect)
308 {
309     DEBUG_ASSERT(src.GetKind() == Operand::kOpdMem, "Just checking");
310     DEBUG_ASSERT(memOrd != AArch64isa::kMoNone, "Just checking");
311 
312     uint32 ssize = isDirect ? src.GetSize() : GetPrimTypeBitSize(dtype);
313     uint32 dsize = GetPrimTypeBitSize(dtype);
314     MOperator mOp = PickLdInsn(ssize, stype, memOrd);
315 
316     Operand *newSrc = &src;
317     auto &memOpnd = static_cast<MemOperand &>(src);
318     OfstOperand *immOpnd = memOpnd.GetOffsetImmediate();
319     int32 offset = static_cast<int32>(immOpnd->GetOffsetValue());
320     RegOperand *origBaseReg = memOpnd.GetBaseRegister();
321     if (offset != 0) {
322         RegOperand &resOpnd = CreateRegisterOperandOfType(PTY_i64);
323         DEBUG_ASSERT(origBaseReg != nullptr, "nullptr check");
324         SelectAdd(resOpnd, *origBaseReg, *immOpnd, PTY_i64);
325         newSrc = &CreateReplacementMemOperand(ssize, resOpnd, 0);
326     }
327 
328     std::string key;
329     if (isDirect && GetCG()->GenerateVerboseCG()) {
330         key = GenerateMemOpndVerbose(src);
331     }
332 
333     /* Check if the right load-acquire instruction is available. */
334     if (mOp != MOP_undef) {
335         Insn &insn = GetInsnBuilder()->BuildInsn(mOp, dest, *newSrc);
336         if (isDirect && GetCG()->GenerateVerboseCG()) {
337             insn.SetComment(key);
338         }
339         GetCurBB()->AppendInsn(insn);
340     } else {
341         if (IsPrimitiveFloat(stype)) {
342             /* Uses signed integer version ldar followed by a floating-point move(fmov).  */
343             DEBUG_ASSERT(stype == dtype, "Just checking");
344             PrimType itype = (stype == PTY_f32) ? PTY_i32 : PTY_i64;
345             RegOperand &regOpnd = CreateRegisterOperandOfType(itype);
346             Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(ssize, itype, memOrd), regOpnd, *newSrc);
347             if (isDirect && GetCG()->GenerateVerboseCG()) {
348                 insn.SetComment(key);
349             }
350             GetCurBB()->AppendInsn(insn);
351             mOp = (stype == PTY_f32) ? MOP_xvmovsr : MOP_xvmovdr;
352             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, regOpnd));
353         } else {
354             /* Use unsigned version ldarb/ldarh followed by a sign-extension instruction(sxtb/sxth).  */
355             DEBUG_ASSERT((ssize == k8BitSize) || (ssize == k16BitSize), "Just checking");
356             PrimType utype = (ssize == k8BitSize) ? PTY_u8 : PTY_u16;
357             Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(ssize, utype, memOrd), dest, *newSrc);
358             if (isDirect && GetCG()->GenerateVerboseCG()) {
359                 insn.SetComment(key);
360             }
361             GetCurBB()->AppendInsn(insn);
362             mOp = ((dsize == k32BitSize) ? ((ssize == k8BitSize) ? MOP_xsxtb32 : MOP_xsxth32)
363                                          : ((ssize == k8BitSize) ? MOP_xsxtb64 : MOP_xsxth64));
364             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, dest));
365         }
366     }
367 }
368 
SelectStoreRelease(Operand & dest,PrimType dtype,Operand & src,PrimType stype,AArch64isa::MemoryOrdering memOrd,bool isDirect)369 void AArch64CGFunc::SelectStoreRelease(Operand &dest, PrimType dtype, Operand &src, PrimType stype,
370                                        AArch64isa::MemoryOrdering memOrd, bool isDirect)
371 {
372     DEBUG_ASSERT(dest.GetKind() == Operand::kOpdMem, "Just checking");
373 
374     uint32 dsize = isDirect ? dest.GetSize() : GetPrimTypeBitSize(stype);
375     MOperator mOp = PickStInsn(dsize, stype, memOrd);
376 
377     Operand *newDest = &dest;
378     MemOperand *memOpnd = static_cast<MemOperand *>(&dest);
379     OfstOperand *immOpnd = memOpnd->GetOffsetImmediate();
380     int32 offset = static_cast<int32>(immOpnd->GetOffsetValue());
381     RegOperand *origBaseReg = memOpnd->GetBaseRegister();
382     if (offset != 0) {
383         RegOperand &resOpnd = CreateRegisterOperandOfType(PTY_i64);
384         DEBUG_ASSERT(origBaseReg != nullptr, "nullptr check");
385         SelectAdd(resOpnd, *origBaseReg, *immOpnd, PTY_i64);
386         newDest = &CreateReplacementMemOperand(dsize, resOpnd, 0);
387     }
388 
389     std::string key;
390     if (isDirect && GetCG()->GenerateVerboseCG()) {
391         key = GenerateMemOpndVerbose(dest);
392     }
393 
394     /* Check if the right store-release instruction is available. */
395     if (mOp != MOP_undef) {
396         Insn &insn = GetInsnBuilder()->BuildInsn(mOp, src, *newDest);
397         if (isDirect && GetCG()->GenerateVerboseCG()) {
398             insn.SetComment(key);
399         }
400         GetCurBB()->AppendInsn(insn);
401     } else {
402         /* Use a floating-point move(fmov) followed by a stlr.  */
403         DEBUG_ASSERT(IsPrimitiveFloat(stype), "must be float type");
404         CHECK_FATAL(stype == dtype, "Just checking");
405         PrimType itype = (stype == PTY_f32) ? PTY_i32 : PTY_i64;
406         RegOperand &regOpnd = CreateRegisterOperandOfType(itype);
407         mOp = (stype == PTY_f32) ? MOP_xvmovrs : MOP_xvmovrd;
408         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, regOpnd, src));
409         Insn &insn = GetInsnBuilder()->BuildInsn(PickStInsn(dsize, itype, memOrd), regOpnd, *newDest);
410         if (isDirect && GetCG()->GenerateVerboseCG()) {
411             insn.SetComment(key);
412         }
413         GetCurBB()->AppendInsn(insn);
414     }
415 }
416 
SelectCopyImm(Operand & dest,PrimType dType,ImmOperand & src,PrimType sType)417 void AArch64CGFunc::SelectCopyImm(Operand &dest, PrimType dType, ImmOperand &src, PrimType sType)
418 {
419     if (IsPrimitiveInteger(dType) != IsPrimitiveInteger(sType)) {
420         RegOperand &tempReg = CreateRegisterOperandOfType(sType);
421         SelectCopyImm(tempReg, src, sType);
422         SelectCopy(dest, dType, tempReg, sType);
423     } else {
424         SelectCopyImm(dest, src, sType);
425     }
426 }
427 
SelectCopyImm(Operand & dest,ImmOperand & src,PrimType dtype)428 void AArch64CGFunc::SelectCopyImm(Operand &dest, ImmOperand &src, PrimType dtype)
429 {
430     uint32 dsize = GetPrimTypeBitSize(dtype);
431     // If the type size of the parent node is smaller than the type size of the child node,
432     // the number of child node needs to be truncated.
433     if (dsize < src.GetSize()) {
434         uint64 value = static_cast<uint64>(src.GetValue());
435         uint64 mask = (1UL << dsize) - 1;
436         int64 newValue = static_cast<int64>(value & mask);
437         src.SetValue(newValue);
438     }
439     DEBUG_ASSERT(IsPrimitiveInteger(dtype), "The type of destination operand must be Integer");
440     DEBUG_ASSERT(((dsize == k8BitSize) || (dsize == k16BitSize) || (dsize == k32BitSize) || (dsize == k64BitSize)),
441                  "The destination operand must be >= 8-bit");
442     if (src.GetSize() == k32BitSize && dsize == k64BitSize && src.IsSingleInstructionMovable()) {
443         auto tempReg = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k32BitSize), k32BitSize, kRegTyInt);
444         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, *tempReg, src));
445         SelectCopy(dest, dtype, *tempReg, PTY_u32);
446         return;
447     }
448     if (src.IsSingleInstructionMovable()) {
449         MOperator mOp = (dsize <= k32BitSize) ? MOP_wmovri32 : MOP_xmovri64;
450         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, src));
451         return;
452     }
453     uint64 srcVal = static_cast<uint64>(src.GetValue());
454     /* using mov/movk to load the immediate value */
455     if (dsize == k8BitSize) {
456         /* compute lower 8 bits value */
457         if (dtype == PTY_u8) {
458             /* zero extend */
459             srcVal = (srcVal << k56BitSize) >> k56BitSize;
460             dtype = PTY_u16;
461         } else {
462             /* sign extend */
463             srcVal = (static_cast<int64>(srcVal) << k56BitSize) >> k56BitSize;
464             dtype = PTY_i16;
465         }
466         dsize = k16BitSize;
467     }
468     if (dsize == k16BitSize) {
469         if (dtype == PTY_u16) {
470             /* check lower 16 bits and higher 16 bits respectively */
471             DEBUG_ASSERT((srcVal & 0x0000FFFFULL) != 0, "unexpected value");
472             DEBUG_ASSERT(((srcVal >> k16BitSize) & 0x0000FFFFULL) == 0, "unexpected value");
473             DEBUG_ASSERT((srcVal & 0x0000FFFFULL) != 0xFFFFULL, "unexpected value");
474             /* create an imm opereand which represents lower 16 bits of the immediate */
475             ImmOperand &srcLower = CreateImmOperand(static_cast<int64>(srcVal & 0x0000FFFFULL), k16BitSize, false);
476             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, dest, srcLower));
477             return;
478         } else {
479             /* sign extend and let `dsize == 32` case take care of it */
480             srcVal = (static_cast<int64>(srcVal) << k48BitSize) >> k48BitSize;
481             dsize = k32BitSize;
482         }
483     }
484     if (dsize == k32BitSize) {
485         /* check lower 16 bits and higher 16 bits respectively */
486         DEBUG_ASSERT((srcVal & 0x0000FFFFULL) != 0, "unexpected val");
487         DEBUG_ASSERT(((srcVal >> k16BitSize) & 0x0000FFFFULL) != 0, "unexpected val");
488         DEBUG_ASSERT((srcVal & 0x0000FFFFULL) != 0xFFFFULL, "unexpected val");
489         DEBUG_ASSERT(((srcVal >> k16BitSize) & 0x0000FFFFULL) != 0xFFFFULL, "unexpected val");
490         /* create an imm opereand which represents lower 16 bits of the immediate */
491         ImmOperand &srcLower = CreateImmOperand(static_cast<int64>(srcVal & 0x0000FFFFULL), k16BitSize, false);
492         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, dest, srcLower));
493         /* create an imm opereand which represents upper 16 bits of the immediate */
494         ImmOperand &srcUpper =
495             CreateImmOperand(static_cast<int64>((srcVal >> k16BitSize) & 0x0000FFFFULL), k16BitSize, false);
496         BitShiftOperand *lslOpnd = GetLogicalShiftLeftOperand(k16BitSize, false);
497         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovkri16, dest, srcUpper, *lslOpnd));
498     } else {
499         /*
500          * partition it into 4 16-bit chunks
501          * if more 0's than 0xFFFF's, use movz as the initial instruction.
502          * otherwise, movn.
503          */
504         bool useMovz = BetterUseMOVZ(srcVal);
505         bool useMovk = false;
506         /* get lower 32 bits of the immediate */
507         uint64 chunkLval = srcVal & 0xFFFFFFFFULL;
508         /* get upper 32 bits of the immediate */
509         uint64 chunkHval = (srcVal >> k32BitSize) & 0xFFFFFFFFULL;
510         int32 maxLoopTime = 4;
511 
512         if (chunkLval == chunkHval) {
513             /* compute lower 32 bits, and then copy to higher 32 bits, so only 2 chunks need be processed */
514             maxLoopTime = 2;
515         }
516 
517         uint64 sa = 0;
518 
519         for (int64 i = 0; i < maxLoopTime; ++i, sa += k16BitSize) {
520             /* create an imm opereand which represents the i-th 16-bit chunk of the immediate */
521             uint64 chunkVal = (srcVal >> (static_cast<uint64>(sa))) & 0x0000FFFFULL;
522             if (useMovz ? (chunkVal == 0) : (chunkVal == 0x0000FFFFULL)) {
523                 continue;
524             }
525             ImmOperand &src16 = CreateImmOperand(static_cast<int64>(chunkVal), k16BitSize, false);
526             BitShiftOperand *lslOpnd = GetLogicalShiftLeftOperand(sa, true);
527             if (!useMovk) {
528                 /* use movz or movn */
529                 if (!useMovz) {
530                     src16.BitwiseNegate();
531                 }
532                 GetCurBB()->AppendInsn(
533                     GetInsnBuilder()->BuildInsn(useMovz ? MOP_xmovzri16 : MOP_xmovnri16, dest, src16, *lslOpnd));
534                 useMovk = true;
535             } else {
536                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xmovkri16, dest, src16, *lslOpnd));
537             }
538         }
539 
540         if (maxLoopTime == 2) { /* as described above, only 2 chunks need be processed */
541             /* copy lower 32 bits to higher 32 bits */
542             ImmOperand &immOpnd = CreateImmOperand(k32BitSize, k8BitSize, false);
543             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xbfirri6i6, dest, dest, immOpnd, immOpnd));
544         }
545     }
546 }
547 
GenerateMemOpndVerbose(const Operand & src) const548 std::string AArch64CGFunc::GenerateMemOpndVerbose(const Operand &src) const
549 {
550     DEBUG_ASSERT(src.GetKind() == Operand::kOpdMem, "Just checking");
551     const MIRSymbol *symSecond = static_cast<const MemOperand *>(&src)->GetSymbol();
552     if (symSecond != nullptr) {
553         std::string key;
554         MIRStorageClass sc = symSecond->GetStorageClass();
555         if (sc == kScFormal) {
556             key = "param: ";
557         } else if (sc == kScAuto) {
558             key = "local var: ";
559         } else {
560             key = "global: ";
561         }
562         key += symSecond->GetName();
563         return key;
564     }
565     return "";
566 }
567 
SelectCopyMemOpnd(Operand & dest,PrimType dtype,uint32 dsize,Operand & src,PrimType stype)568 void AArch64CGFunc::SelectCopyMemOpnd(Operand &dest, PrimType dtype, uint32 dsize, Operand &src, PrimType stype)
569 {
570     AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone;
571     const MIRSymbol *sym = static_cast<MemOperand *>(&src)->GetSymbol();
572     if ((sym != nullptr) && (sym->GetStorageClass() == kScGlobal) && sym->GetAttr(ATTR_memory_order_acquire)) {
573         memOrd = AArch64isa::kMoAcquire;
574     }
575 
576     if (memOrd != AArch64isa::kMoNone) {
577         AArch64CGFunc::SelectLoadAcquire(dest, dtype, src, stype, memOrd, true);
578         return;
579     }
580     Insn *insn = nullptr;
581     uint32 ssize = src.GetSize();
582     PrimType regTy = PTY_void;
583     RegOperand *loadReg = nullptr;
584     MOperator mop = MOP_undef;
585     if (IsPrimitiveFloat(stype) || IsPrimitiveVector(stype)) {
586         CHECK_FATAL(dsize == ssize, "dsize %u expect equals ssize %u", dtype, ssize);
587         insn = &GetInsnBuilder()->BuildInsn(PickLdInsn(ssize, stype), dest, src);
588     } else {
589         if (stype == PTY_agg && dtype == PTY_agg) {
590             mop = MOP_undef;
591         } else {
592             mop = PickExtInsn(dtype, stype);
593         }
594         if (ssize == (GetPrimTypeSize(dtype) * kBitsPerByte) || mop == MOP_undef) {
595             insn = &GetInsnBuilder()->BuildInsn(PickLdInsn(ssize, stype), dest, src);
596         } else {
597             regTy = dsize == k64BitSize ? dtype : PTY_i32;
598             loadReg = &CreateRegisterOperandOfType(regTy);
599             insn = &GetInsnBuilder()->BuildInsn(PickLdInsn(ssize, stype), *loadReg, src);
600         }
601     }
602 
603     if (GetCG()->GenerateVerboseCG()) {
604         insn->SetComment(GenerateMemOpndVerbose(src));
605     }
606 
607     GetCurBB()->AppendInsn(*insn);
608     if (regTy != PTY_void && mop != MOP_undef) {
609         DEBUG_ASSERT(loadReg != nullptr, "loadReg should not be nullptr");
610         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, dest, *loadReg));
611     }
612 }
613 
IsImmediateValueInRange(MOperator mOp,int64 immVal,bool is64Bits,bool isIntactIndexed,bool isPostIndexed,bool isPreIndexed) const614 bool AArch64CGFunc::IsImmediateValueInRange(MOperator mOp, int64 immVal, bool is64Bits, bool isIntactIndexed,
615                                             bool isPostIndexed, bool isPreIndexed) const
616 {
617     bool isInRange = false;
618     switch (mOp) {
619         case MOP_xstr:
620         case MOP_wstr:
621             isInRange =
622                 (isIntactIndexed &&
623                  ((!is64Bits && (immVal >= kStrAllLdrAllImmLowerBound) && (immVal <= kStrLdrImm32UpperBound)) ||
624                   (is64Bits && (immVal >= kStrAllLdrAllImmLowerBound) && (immVal <= kStrLdrImm64UpperBound)))) ||
625                 ((isPostIndexed || isPreIndexed) && (immVal >= kStrLdrPerPostLowerBound) &&
626                  (immVal <= kStrLdrPerPostUpperBound));
627             break;
628         case MOP_wstrb:
629             isInRange =
630                 (isIntactIndexed && (immVal >= kStrAllLdrAllImmLowerBound) && (immVal <= kStrbLdrbImmUpperBound)) ||
631                 ((isPostIndexed || isPreIndexed) && (immVal >= kStrLdrPerPostLowerBound) &&
632                  (immVal <= kStrLdrPerPostUpperBound));
633             break;
634         case MOP_wstrh:
635             isInRange =
636                 (isIntactIndexed && (immVal >= kStrAllLdrAllImmLowerBound) && (immVal <= kStrhLdrhImmUpperBound)) ||
637                 ((isPostIndexed || isPreIndexed) && (immVal >= kStrLdrPerPostLowerBound) &&
638                  (immVal <= kStrLdrPerPostUpperBound));
639             break;
640         default:
641             break;
642     }
643     return isInRange;
644 }
645 
IsStoreMop(MOperator mOp) const646 bool AArch64CGFunc::IsStoreMop(MOperator mOp) const
647 {
648     switch (mOp) {
649         case MOP_sstr:
650         case MOP_dstr:
651         case MOP_qstr:
652         case MOP_xstr:
653         case MOP_wstr:
654         case MOP_wstrb:
655         case MOP_wstrh:
656             return true;
657         default:
658             return false;
659     }
660 }
661 
SplitMovImmOpndInstruction(int64 immVal,RegOperand & destReg,Insn * curInsn)662 void AArch64CGFunc::SplitMovImmOpndInstruction(int64 immVal, RegOperand &destReg, Insn *curInsn)
663 {
664     bool useMovz = BetterUseMOVZ(immVal);
665     bool useMovk = false;
666     /* get lower 32 bits of the immediate */
667     uint64 chunkLval = static_cast<uint64>(immVal) & 0xFFFFFFFFULL;
668     /* get upper 32 bits of the immediate */
669     uint64 chunkHval = (static_cast<uint64>(immVal) >> k32BitSize) & 0xFFFFFFFFULL;
670     int32 maxLoopTime = 4;
671 
672     if (chunkLval == chunkHval) {
673         /* compute lower 32 bits, and then copy to higher 32 bits, so only 2 chunks need be processed */
674         maxLoopTime = 2;
675     }
676 
677     uint64 sa = 0;
678     auto *bb = (curInsn != nullptr) ? curInsn->GetBB() : GetCurBB();
679     for (int64 i = 0; i < maxLoopTime; ++i, sa += k16BitSize) {
680         /* create an imm opereand which represents the i-th 16-bit chunk of the immediate */
681         uint64 chunkVal = (static_cast<uint64>(immVal) >> sa) & 0x0000FFFFULL;
682         if (useMovz ? (chunkVal == 0) : (chunkVal == 0x0000FFFFULL)) {
683             continue;
684         }
685         ImmOperand &src16 = CreateImmOperand(static_cast<int64>(chunkVal), k16BitSize, false);
686         BitShiftOperand *lslOpnd = GetLogicalShiftLeftOperand(sa, true);
687         Insn *newInsn = nullptr;
688         if (!useMovk) {
689             /* use movz or movn */
690             if (!useMovz) {
691                 src16.BitwiseNegate();
692             }
693             MOperator mOpCode = useMovz ? MOP_xmovzri16 : MOP_xmovnri16;
694             newInsn = &GetInsnBuilder()->BuildInsn(mOpCode, destReg, src16, *lslOpnd);
695             useMovk = true;
696         } else {
697             newInsn = &GetInsnBuilder()->BuildInsn(MOP_xmovkri16, destReg, src16, *lslOpnd);
698         }
699         if (curInsn != nullptr) {
700             bb->InsertInsnBefore(*curInsn, *newInsn);
701         } else {
702             bb->AppendInsn(*newInsn);
703         }
704     }
705 
706     if (maxLoopTime == 2) {  // compute lower 32 bits, and copy to higher 32 bits, so only 2 chunks need be processed
707         /* copy lower 32 bits to higher 32 bits */
708         ImmOperand &immOpnd = CreateImmOperand(k32BitSize, k8BitSize, false);
709         Insn &insn = GetInsnBuilder()->BuildInsn(MOP_xbfirri6i6, destReg, destReg, immOpnd, immOpnd);
710         if (curInsn != nullptr) {
711             bb->InsertInsnBefore(*curInsn, insn);
712         } else {
713             bb->AppendInsn(insn);
714         }
715     }
716 }
717 
SelectCopyRegOpnd(Operand & dest,PrimType dtype,Operand::OperandType opndType,uint32 dsize,Operand & src,PrimType stype)718 void AArch64CGFunc::SelectCopyRegOpnd(Operand &dest, PrimType dtype, Operand::OperandType opndType, uint32 dsize,
719                                       Operand &src, PrimType stype)
720 {
721     if (opndType != Operand::kOpdMem) {
722         if (!CGOptions::IsArm64ilp32()) {
723             DEBUG_ASSERT(stype != PTY_a32, "");
724         }
725         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickMovBetweenRegs(dtype, stype), dest, src));
726         return;
727     }
728     AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone;
729     const MIRSymbol *sym = static_cast<MemOperand *>(&dest)->GetSymbol();
730     if ((sym != nullptr) && (sym->GetStorageClass() == kScGlobal) && sym->GetAttr(ATTR_memory_order_release)) {
731         memOrd = AArch64isa::kMoRelease;
732     }
733 
734     if (memOrd != AArch64isa::kMoNone) {
735         AArch64CGFunc::SelectStoreRelease(dest, dtype, src, stype, memOrd, true);
736         return;
737     }
738 
739     bool is64Bits = (dest.GetSize() == k64BitSize) ? true : false;
740     MOperator strMop = PickStInsn(dsize, stype);
741     if (!dest.IsMemoryAccessOperand()) {
742         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(strMop, src, dest));
743         return;
744     }
745 
746     MemOperand *memOpnd = static_cast<MemOperand *>(&dest);
747     DEBUG_ASSERT(memOpnd != nullptr, "memOpnd should not be nullptr");
748     if (memOpnd->GetAddrMode() == MemOperand::kAddrModeLo12Li) {
749         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(strMop, src, dest));
750         return;
751     }
752     if (memOpnd->GetOffsetOperand() == nullptr) {
753         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(strMop, src, dest));
754         return;
755     }
756     ImmOperand *immOpnd = static_cast<ImmOperand *>(memOpnd->GetOffsetOperand());
757     DEBUG_ASSERT(immOpnd != nullptr, "immOpnd should not be nullptr");
758     int64 immVal = immOpnd->GetValue();
759     bool isIntactIndexed = memOpnd->IsIntactIndexed();
760     bool isPostIndexed = memOpnd->IsPostIndexed();
761     bool isPreIndexed = memOpnd->IsPreIndexed();
762     DEBUG_ASSERT(!isPostIndexed, "memOpnd should not be post-index type");
763     DEBUG_ASSERT(!isPreIndexed, "memOpnd should not be pre-index type");
764     bool isInRange = false;
765     if (!GetMirModule().IsCModule()) {
766         isInRange = IsImmediateValueInRange(strMop, immVal, is64Bits, isIntactIndexed, isPostIndexed, isPreIndexed);
767     } else {
768         isInRange = IsOperandImmValid(strMop, memOpnd, kInsnSecondOpnd);
769     }
770     bool isMopStr = IsStoreMop(strMop);
771     if (isInRange || !isMopStr) {
772         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(strMop, src, dest));
773         return;
774     }
775     DEBUG_ASSERT(memOpnd->GetBaseRegister() != nullptr, "nullptr check");
776     if (isIntactIndexed) {
777         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, dsize);
778         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(strMop, src, *memOpnd));
779     } else if (isPostIndexed || isPreIndexed) {
780         RegOperand &reg = CreateRegisterOperandOfType(PTY_i64);
781         MOperator mopMov = MOP_xmovri64;
782         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopMov, reg, *immOpnd));
783         MOperator mopAdd = MOP_xaddrrr;
784         MemOperand &newDest =
785             GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, GetPrimTypeBitSize(dtype), memOpnd->GetBaseRegister(), nullptr,
786                                &GetOrCreateOfstOpnd(0, k32BitSize), nullptr);
787         Insn &insn1 = GetInsnBuilder()->BuildInsn(strMop, src, newDest);
788         Insn &insn2 = GetInsnBuilder()->BuildInsn(mopAdd, *newDest.GetBaseRegister(), *newDest.GetBaseRegister(), reg);
789         if (isPostIndexed) {
790             GetCurBB()->AppendInsn(insn1);
791             GetCurBB()->AppendInsn(insn2);
792         } else {
793             /* isPreIndexed */
794             GetCurBB()->AppendInsn(insn2);
795             GetCurBB()->AppendInsn(insn1);
796         }
797     }
798 }
799 
SelectCopy(Operand & dest,PrimType dtype,Operand & src,PrimType stype,BaseNode * baseNode)800 void AArch64CGFunc::SelectCopy(Operand &dest, PrimType dtype, Operand &src, PrimType stype, BaseNode *baseNode)
801 {
802     DEBUG_ASSERT(dest.IsRegister() || dest.IsMemoryAccessOperand(), "");
803     uint32 dsize = GetPrimTypeBitSize(dtype);
804     if (dest.IsRegister()) {
805         dsize = dest.GetSize();
806     }
807     Operand::OperandType opnd0Type = dest.GetKind();
808     Operand::OperandType opnd1Type = src.GetKind();
809     DEBUG_ASSERT(((dsize >= src.GetSize()) || (opnd0Type == Operand::kOpdRegister) || (opnd0Type == Operand::kOpdMem)),
810                  "NYI");
811     DEBUG_ASSERT(((opnd0Type == Operand::kOpdRegister) || (src.GetKind() == Operand::kOpdRegister)),
812                  "either src or dest should be register");
813 
814     switch (opnd1Type) {
815         case Operand::kOpdMem:
816             SelectCopyMemOpnd(dest, dtype, dsize, src, stype);
817             break;
818         case Operand::kOpdOffset:
819         case Operand::kOpdImmediate:
820             SelectCopyImm(dest, dtype, static_cast<ImmOperand &>(src), stype);
821             break;
822         case Operand::kOpdFPImmediate:
823             CHECK_FATAL(static_cast<ImmOperand &>(src).GetValue() == 0, "NIY");
824             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn((dsize == k32BitSize) ? MOP_xvmovsr : MOP_xvmovdr, dest,
825                                                                GetZeroOpnd(dsize)));
826             break;
827         case Operand::kOpdRegister: {
828             if (opnd0Type == Operand::kOpdRegister && IsPrimitiveVector(stype)) {
829                 /* check vector reg to vector reg move */
830                 CHECK_FATAL(IsPrimitiveVector(dtype), "invalid vectreg to vectreg move");
831                 MOperator mop = (dsize <= k64BitSize) ? MOP_vmovuu : MOP_vmovvv;
832                 VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
833                 vInsn.AddOpndChain(dest).AddOpndChain(src);
834                 auto *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(dsize >> k3ByteSize, k8BitSize);
835                 auto *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(dsize >> k3ByteSize, k8BitSize);
836                 vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecSrc);
837                 GetCurBB()->AppendInsn(vInsn);
838                 break;
839             }
840             if (dest.IsRegister()) {
841                 RegOperand &desReg = static_cast<RegOperand &>(dest);
842                 RegOperand &srcReg = static_cast<RegOperand &>(src);
843                 if (desReg.GetRegisterNumber() == srcReg.GetRegisterNumber()) {
844                     break;
845                 }
846             }
847             SelectCopyRegOpnd(dest, dtype, opnd0Type, dsize, src, stype);
848             break;
849         }
850         default:
851             CHECK_FATAL(false, "NYI");
852     }
853 }
854 
855 /* This function copies src to a register, the src can be an imm, mem or a label */
SelectCopy(Operand & src,PrimType stype,PrimType dtype)856 RegOperand &AArch64CGFunc::SelectCopy(Operand &src, PrimType stype, PrimType dtype)
857 {
858     RegOperand &dest = CreateRegisterOperandOfType(dtype);
859     SelectCopy(dest, dtype, src, stype);
860     return dest;
861 }
862 
863 /*
864  * We need to adjust the offset of a stack allocated local variable
865  * if we store FP/SP before any other local variables to save an instruction.
866  * See AArch64CGFunc::OffsetAdjustmentForFPLR() in aarch64_cgfunc.cpp
867  *
868  * That is when we !UsedStpSubPairForCallFrameAllocation().
869  *
870  * Because we need to use the STP/SUB instruction pair to store FP/SP 'after'
871  * local variables when the call frame size is greater that the max offset
872  * value allowed for the STP instruction (we cannot use STP w/ prefix, LDP w/
873  * postfix), if UsedStpSubPairForCallFrameAllocation(), we don't need to
874  * adjust the offsets.
875  */
IsImmediateOffsetOutOfRange(const MemOperand & memOpnd,uint32 bitLen)876 bool AArch64CGFunc::IsImmediateOffsetOutOfRange(const MemOperand &memOpnd, uint32 bitLen)
877 {
878     DEBUG_ASSERT(bitLen >= k8BitSize, "bitlen error");
879     DEBUG_ASSERT(bitLen <= k128BitSize, "bitlen error");
880 
881     if (bitLen >= k8BitSize) {
882         bitLen = static_cast<uint32>(RoundUp(bitLen, k8BitSize));
883     }
884     DEBUG_ASSERT((bitLen & (bitLen - 1)) == 0, "bitlen error");
885 
886     MemOperand::AArch64AddressingMode mode = memOpnd.GetAddrMode();
887     if ((mode == MemOperand::kAddrModeBOi) && memOpnd.IsIntactIndexed()) {
888         OfstOperand *ofstOpnd = memOpnd.GetOffsetImmediate();
889         int32 offsetValue = ofstOpnd ? static_cast<int32>(ofstOpnd->GetOffsetValue()) : 0;
890         if (ofstOpnd && ofstOpnd->GetVary() == kUnAdjustVary) {
891             offsetValue +=
892                 static_cast<int32>(static_cast<AArch64MemLayout *>(GetMemlayout())->RealStackFrameSize() + 0xff);
893         }
894         offsetValue += kAarch64IntregBytelen << 1; /* Refer to the above comment */
895         return MemOperand::IsPIMMOffsetOutOfRange(offsetValue, bitLen);
896     } else {
897         return false;
898     }
899 }
900 
901 // This api is used to judge whether opnd is legal for mop.
902 // It is implemented by calling verify api of mop (InsnDesc -> Verify).
IsOperandImmValid(MOperator mOp,Operand * o,uint32 opndIdx) const903 bool AArch64CGFunc::IsOperandImmValid(MOperator mOp, Operand *o, uint32 opndIdx) const
904 {
905     const InsnDesc *md = &AArch64CG::kMd[mOp];
906     auto *opndProp = md->opndMD[opndIdx];
907     MemPool *localMp = memPoolCtrler.NewMemPool("opnd verify mempool", true);
908     auto *localAlloc = new MapleAllocator(localMp);
909     MapleVector<Operand *> testOpnds(md->opndMD.size(), localAlloc->Adapter());
910     testOpnds[opndIdx] = o;
911     bool flag = true;
912     Operand::OperandType opndTy = opndProp->GetOperandType();
913     if (opndTy == Operand::kOpdMem) {
914         auto *memOpnd = static_cast<MemOperand *>(o);
915         CHECK_FATAL(memOpnd != nullptr, "memOpnd should not be nullptr");
916         if (memOpnd->GetAddrMode() == MemOperand::kAddrModeBOrX &&
917             (!memOpnd->IsPostIndexed() && !memOpnd->IsPreIndexed())) {
918             delete localAlloc;
919             memPoolCtrler.DeleteMemPool(localMp);
920             return true;
921         }
922         OfstOperand *ofStOpnd = memOpnd->GetOffsetImmediate();
923         int64 offsetValue = ofStOpnd ? ofStOpnd->GetOffsetValue() : 0LL;
924         if (md->IsLoadStorePair() || (memOpnd->GetAddrMode() == MemOperand::kAddrModeBOi)) {
925             flag = md->Verify(testOpnds);
926         } else if (memOpnd->GetAddrMode() == MemOperand::kAddrModeLo12Li) {
927             if (offsetValue == 0) {
928                 flag = md->Verify(testOpnds);
929             } else {
930                 flag = false;
931             }
932         } else if (memOpnd->IsPostIndexed() || memOpnd->IsPreIndexed()) {
933             flag = (offsetValue <= static_cast<int64>(k256BitSizeInt) && offsetValue >= kNegative256BitSize);
934         }
935     } else if (opndTy == Operand::kOpdImmediate) {
936         flag = md->Verify(testOpnds);
937     }
938     delete localAlloc;
939     memPoolCtrler.DeleteMemPool(localMp);
940     return flag;
941 }
942 
CreateReplacementMemOperand(uint32 bitLen,RegOperand & baseReg,int64 offset)943 MemOperand &AArch64CGFunc::CreateReplacementMemOperand(uint32 bitLen, RegOperand &baseReg, int64 offset)
944 {
945     return CreateMemOpnd(baseReg, offset, bitLen);
946 }
947 
CheckIfSplitOffsetWithAdd(const MemOperand & memOpnd,uint32 bitLen) const948 bool AArch64CGFunc::CheckIfSplitOffsetWithAdd(const MemOperand &memOpnd, uint32 bitLen) const
949 {
950     if (memOpnd.GetAddrMode() != MemOperand::kAddrModeBOi || !memOpnd.IsIntactIndexed()) {
951         return false;
952     }
953     OfstOperand *ofstOpnd = memOpnd.GetOffsetImmediate();
954     int32 opndVal = static_cast<int32>(ofstOpnd->GetOffsetValue());
955     int32 maxPimm = memOpnd.GetMaxPIMM(bitLen);
956     int32 q0 = opndVal / maxPimm;
957     int32 addend = q0 * maxPimm;
958     int32 r0 = opndVal - addend;
959     int32 alignment = static_cast<int32_t>(memOpnd.GetImmediateOffsetAlignment(bitLen));
960     int32 r1 = static_cast<uint32>(r0) & ((1u << static_cast<uint32>(alignment)) - 1);
961     addend = addend + r1;
962     return (addend > 0);
963 }
964 
GetBaseRegForSplit(uint32 baseRegNum)965 RegOperand *AArch64CGFunc::GetBaseRegForSplit(uint32 baseRegNum)
966 {
967     RegOperand *resOpnd = nullptr;
968     if (baseRegNum == AArch64reg::kRinvalid) {
969         resOpnd = &CreateRegisterOperandOfType(PTY_i64);
970     } else if (AArch64isa::IsPhysicalRegister(baseRegNum)) {
971         resOpnd = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(baseRegNum),
972                                                       GetPointerSize() * kBitsPerByte, kRegTyInt);
973     } else {
974         resOpnd = &GetOrCreateVirtualRegisterOperand(baseRegNum);
975     }
976     return resOpnd;
977 }
978 
979 /*
980  * When immediate of str/ldr is over 256bits, it should be aligned according to the reg byte size.
981  * Here we split the offset into (512 * n) and +/-(new Offset) when misaligned, to make sure that
982  * the new offet is always under 256 bits.
983  */
ConstraintOffsetToSafeRegion(uint32 bitLen,const MemOperand & memOpnd,const MIRSymbol * symbol)984 MemOperand &AArch64CGFunc::ConstraintOffsetToSafeRegion(uint32 bitLen, const MemOperand &memOpnd,
985                                                         const MIRSymbol *symbol)
986 {
987     auto it = hashMemOpndTable.find(memOpnd);
988     if (it != hashMemOpndTable.end()) {
989         hashMemOpndTable.erase(memOpnd);
990     }
991     MemOperand::AArch64AddressingMode addrMode = memOpnd.GetAddrMode();
992     int32 offsetValue = static_cast<int32>(memOpnd.GetOffsetImmediate()->GetOffsetValue());
993     RegOperand *baseReg = memOpnd.GetBaseRegister();
994     RegOperand *resOpnd = GetBaseRegForSplit(kRinvalid);
995     MemOperand *newMemOpnd = nullptr;
996     if (addrMode == MemOperand::kAddrModeBOi) {
997         int32 val256 = k256BitSizeInt; /* const val is unsigned */
998         int32 val512 = k512BitSizeInt;
999         int32 multiplier = (offsetValue / val512) + static_cast<int32>(offsetValue % val512 > val256);
1000         int32 addMount = multiplier * val512;
1001         int32 newOffset = offsetValue - addMount;
1002         ImmOperand &immAddMount = CreateImmOperand(addMount, k64BitSize, true);
1003         if (memOpnd.GetOffsetImmediate()->GetVary() == kUnAdjustVary) {
1004             immAddMount.SetVary(kUnAdjustVary);
1005         }
1006         SelectAdd(*resOpnd, *baseReg, immAddMount, PTY_i64);
1007         newMemOpnd = &CreateReplacementMemOperand(bitLen, *resOpnd, newOffset);
1008     } else if (addrMode == MemOperand::kAddrModeLo12Li) {
1009         CHECK_FATAL(symbol != nullptr, "must have symbol");
1010         StImmOperand &stImmOpnd = CreateStImmOperand(*symbol, offsetValue, 0);
1011         SelectAdd(*resOpnd, *baseReg, stImmOpnd, PTY_i64);
1012         newMemOpnd = &CreateReplacementMemOperand(bitLen, *resOpnd, 0);
1013     }
1014     CHECK_FATAL(newMemOpnd != nullptr, "create memOpnd failed");
1015     newMemOpnd->SetStackMem(memOpnd.IsStackMem());
1016     return *newMemOpnd;
1017 }
1018 
SplitAndGetRemained(const MemOperand & memOpnd,uint32 bitLen,RegOperand * resOpnd,int64 ofstVal,bool isDest,Insn * insn,bool forPair)1019 ImmOperand &AArch64CGFunc::SplitAndGetRemained(const MemOperand &memOpnd, uint32 bitLen, RegOperand *resOpnd,
1020                                                int64 ofstVal, bool isDest, Insn *insn, bool forPair)
1021 {
1022     auto it = hashMemOpndTable.find(memOpnd);
1023     if (it != hashMemOpndTable.end()) {
1024         hashMemOpndTable.erase(memOpnd);
1025     }
1026     /*
1027      * opndVal == Q0 * 32760(16380) + R0
1028      * R0 == Q1 * 8(4) + R1
1029      * ADDEND == Q0 * 32760(16380) + R1
1030      * NEW_OFFSET = Q1 * 8(4)
1031      * we want to generate two instructions:
1032      * ADD TEMP_REG, X29, ADDEND
1033      * LDR/STR TEMP_REG, [ TEMP_REG, #NEW_OFFSET ]
1034      */
1035     int32 maxPimm = 0;
1036     if (!forPair) {
1037         maxPimm = MemOperand::GetMaxPIMM(bitLen);
1038     } else {
1039         maxPimm = MemOperand::GetMaxPairPIMM(bitLen);
1040     }
1041     DEBUG_ASSERT(maxPimm != 0, "get max pimm failed");
1042 
1043     int64 q0 = ofstVal / maxPimm + (ofstVal < 0 ? -1 : 0);
1044     int64 addend = q0 * maxPimm;
1045     int64 r0 = ofstVal - addend;
1046     int64 alignment = MemOperand::GetImmediateOffsetAlignment(bitLen);
1047     auto q1 = static_cast<int64>(static_cast<uint64>(r0) >> static_cast<uint64>(alignment));
1048     auto r1 = static_cast<int64>(static_cast<uint64>(r0) & ((1u << static_cast<uint64>(alignment)) - 1));
1049     auto remained = static_cast<int64>(static_cast<uint64>(q1) << static_cast<uint64>(alignment));
1050     addend = addend + r1;
1051     if (addend > 0) {
1052         int64 suffixClear = 0xfff;
1053         if (forPair) {
1054             suffixClear = 0xff;
1055         }
1056         int64 remainedTmp = remained + (addend & suffixClear);
1057         if (!MemOperand::IsPIMMOffsetOutOfRange(static_cast<int32>(remainedTmp), bitLen) &&
1058             ((static_cast<uint64>(remainedTmp) & ((1u << static_cast<uint64>(alignment)) - 1)) == 0)) {
1059             remained = remainedTmp;
1060             addend = (addend & ~suffixClear);
1061         }
1062     }
1063     ImmOperand &immAddend = CreateImmOperand(addend, k64BitSize, true);
1064     if (memOpnd.GetOffsetImmediate()->GetVary() == kUnAdjustVary) {
1065         immAddend.SetVary(kUnAdjustVary);
1066     }
1067     return immAddend;
1068 }
1069 
SplitOffsetWithAddInstruction(const MemOperand & memOpnd,uint32 bitLen,uint32 baseRegNum,bool isDest,Insn * insn,bool forPair)1070 MemOperand &AArch64CGFunc::SplitOffsetWithAddInstruction(const MemOperand &memOpnd, uint32 bitLen, uint32 baseRegNum,
1071                                                          bool isDest, Insn *insn, bool forPair)
1072 {
1073     DEBUG_ASSERT((memOpnd.GetAddrMode() == MemOperand::kAddrModeBOi), "expect kAddrModeBOi memOpnd");
1074     DEBUG_ASSERT(memOpnd.IsIntactIndexed(), "expect intactIndexed memOpnd");
1075     OfstOperand *ofstOpnd = memOpnd.GetOffsetImmediate();
1076     int64 ofstVal = ofstOpnd->GetOffsetValue();
1077     RegOperand *resOpnd = GetBaseRegForSplit(baseRegNum);
1078     ImmOperand &immAddend = SplitAndGetRemained(memOpnd, bitLen, resOpnd, ofstVal, isDest, insn, forPair);
1079     int64 remained = (ofstVal - immAddend.GetValue());
1080     RegOperand *origBaseReg = memOpnd.GetBaseRegister();
1081     DEBUG_ASSERT(origBaseReg != nullptr, "nullptr check");
1082     if (insn == nullptr) {
1083         SelectAdd(*resOpnd, *origBaseReg, immAddend, PTY_i64);
1084     } else {
1085         SelectAddAfterInsn(*resOpnd, *origBaseReg, immAddend, PTY_i64, isDest, *insn);
1086     }
1087     MemOperand &newMemOpnd = CreateReplacementMemOperand(bitLen, *resOpnd, remained);
1088     newMemOpnd.SetStackMem(memOpnd.IsStackMem());
1089     return newMemOpnd;
1090 }
1091 
SelectDassign(DassignNode & stmt,Operand & opnd0)1092 void AArch64CGFunc::SelectDassign(DassignNode &stmt, Operand &opnd0)
1093 {
1094     SelectDassign(stmt.GetStIdx(), stmt.GetFieldID(), stmt.GetRHS()->GetPrimType(), opnd0);
1095 }
1096 
1097 /* Extract the address of memOpnd.
1098  *  1. memcpy need address from memOpnd
1099  *  2. Used for SelectDassign when do optimization for volatile store, because the stlr instruction only allow
1100  *     store to the memory addrress with the register base offset 0.
1101  *     STLR <Wt>, [<Xn|SP>{,#0}], 32-bit variant (size = 10)
1102  *     STLR <Xt>, [<Xn|SP>{,#0}], 64-bit variant (size = 11)
1103  */
ExtractMemBaseAddr(const MemOperand & memOpnd)1104 RegOperand *AArch64CGFunc::ExtractMemBaseAddr(const MemOperand &memOpnd)
1105 {
1106     const MIRSymbol *sym = memOpnd.GetSymbol();
1107     MemOperand::AArch64AddressingMode mode = memOpnd.GetAddrMode();
1108     if (mode == MemOperand::kAddrModeLiteral) {
1109         return nullptr;
1110     }
1111     RegOperand *baseOpnd = memOpnd.GetBaseRegister();
1112     OfstOperand *offsetOpnd = memOpnd.GetOffsetImmediate();
1113     int64 offset = (offsetOpnd == nullptr ? 0 : offsetOpnd->GetOffsetValue());
1114     DEBUG_ASSERT(baseOpnd != nullptr, "nullptr check");
1115     RegOperand &resultOpnd =
1116         CreateRegisterOperandOfType(baseOpnd->GetRegisterType(), baseOpnd->GetSize() / kBitsPerByte);
1117     bool is64Bits = (baseOpnd->GetSize() == k64BitSize);
1118     if (mode == MemOperand::kAddrModeLo12Li) {
1119         StImmOperand &stImm = CreateStImmOperand(*sym, offset, 0);
1120         Insn &addInsn = GetInsnBuilder()->BuildInsn(MOP_xadrpl12, resultOpnd, *baseOpnd, stImm);
1121         addInsn.SetComment("new add insn");
1122         GetCurBB()->AppendInsn(addInsn);
1123     } else if (mode == MemOperand::kAddrModeBOi) {
1124         if ((offsetOpnd != nullptr) && (offsetOpnd->GetOffsetValue() != 0)) {
1125             MOperator mOp = is64Bits ? MOP_xaddrri12 : MOP_waddrri12;
1126             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resultOpnd, *baseOpnd, *offsetOpnd));
1127         } else {
1128             return baseOpnd;
1129         }
1130     } else {
1131         CHECK_FATAL(mode == MemOperand::kAddrModeBOrX, "unexpect addressing mode.");
1132         RegOperand *regOpnd = static_cast<const MemOperand *>(&memOpnd)->GetIndexRegister();
1133         MOperator mOp = is64Bits ? MOP_xaddrrr : MOP_waddrrr;
1134         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resultOpnd, *baseOpnd, *regOpnd));
1135     }
1136     return &resultOpnd;
1137 }
1138 
1139 /*
1140  * NOTE: I divided SelectDassign so that we can create "virtual" assignments
1141  * when selecting other complex Maple IR instructions. For example, the atomic
1142  * exchange and other intrinsics will need to assign its results to local
1143  * variables. Such Maple IR instructions are pltform-specific (e.g.
1144  * atomic_exchange can be implemented as one single machine intruction on x86_64
1145  * and ARMv8.1, but ARMv8.0 needs an LL/SC loop), therefore they cannot (in
1146  * principle) be lowered at BELowerer or CGLowerer.
1147  */
SelectDassign(StIdx stIdx,FieldID fieldId,PrimType rhsPType,Operand & opnd0)1148 void AArch64CGFunc::SelectDassign(StIdx stIdx, FieldID fieldId, PrimType rhsPType, Operand &opnd0)
1149 {
1150     MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(stIdx);
1151     int32 offset = 0;
1152     bool parmCopy = false;
1153     if (fieldId != 0) {
1154         MIRStructType *structType = static_cast<MIRStructType *>(symbol->GetType());
1155         DEBUG_ASSERT(structType != nullptr, "SelectDassign: non-zero fieldID for non-structure");
1156         offset = GetBecommon().GetFieldOffset(*structType, fieldId).first;
1157         parmCopy = IsParamStructCopy(*symbol);
1158     }
1159     uint32 regSize = GetPrimTypeBitSize(rhsPType);
1160     MIRType *type = symbol->GetType();
1161     Operand &stOpnd = LoadIntoRegister(opnd0, IsPrimitiveInteger(rhsPType) || IsPrimitiveVectorInteger(rhsPType),
1162                                        regSize, IsSignedInteger(type->GetPrimType()));
1163     MOperator mOp = MOP_undef;
1164     if ((type->GetKind() == kTypeStruct) || (type->GetKind() == kTypeUnion)) {
1165         MIRStructType *structType = static_cast<MIRStructType *>(type);
1166         type = structType->GetFieldType(fieldId);
1167     } else if (type->GetKind() == kTypeClass) {
1168         MIRClassType *classType = static_cast<MIRClassType *>(type);
1169         type = classType->GetFieldType(fieldId);
1170     }
1171 
1172     uint32 dataSize = GetPrimTypeBitSize(type->GetPrimType());
1173     if (type->GetPrimType() == PTY_agg) {
1174         dataSize = GetPrimTypeBitSize(PTY_a64);
1175     }
1176     MemOperand *memOpnd = nullptr;
1177     if (parmCopy) {
1178         memOpnd = &LoadStructCopyBase(*symbol, offset, static_cast<int>(dataSize));
1179     } else {
1180         memOpnd = &GetOrCreateMemOpnd(*symbol, offset, dataSize);
1181     }
1182     if ((memOpnd->GetMemVaryType() == kNotVary) && IsImmediateOffsetOutOfRange(*memOpnd, dataSize)) {
1183         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, dataSize);
1184     }
1185 
1186     /* In bpl mode, a func symbol's type is represented as a MIRFuncType instead of a MIRPtrType (pointing to
1187      * MIRFuncType), so we allow `kTypeFunction` to appear here */
1188     DEBUG_ASSERT(((type->GetKind() == kTypeScalar) || (type->GetKind() == kTypePointer) ||
1189                   (type->GetKind() == kTypeFunction) || (type->GetKind() == kTypeStruct) ||
1190                   (type->GetKind() == kTypeUnion) || (type->GetKind() == kTypeArray)),
1191                  "NYI dassign type");
1192     PrimType ptyp = type->GetPrimType();
1193     if (ptyp == PTY_agg) {
1194         ptyp = PTY_a64;
1195     }
1196 
1197     AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone;
1198     if (isVolStore) {
1199         RegOperand *baseOpnd = ExtractMemBaseAddr(*memOpnd);
1200         if (baseOpnd != nullptr) {
1201             memOpnd = &CreateMemOpnd(*baseOpnd, 0, dataSize);
1202             memOrd = AArch64isa::kMoRelease;
1203             isVolStore = false;
1204         }
1205     }
1206 
1207     memOpnd =
1208         memOpnd->IsOffsetMisaligned(dataSize) ? &ConstraintOffsetToSafeRegion(dataSize, *memOpnd, symbol) : memOpnd;
1209     if (symbol->GetAsmAttr() != UStrIdx(0) && symbol->GetStorageClass() != kScPstatic &&
1210         symbol->GetStorageClass() != kScFstatic) {
1211         std::string regDesp = GlobalTables::GetUStrTable().GetStringFromStrIdx(symbol->GetAsmAttr());
1212         RegOperand &specifiedOpnd = GetOrCreatePhysicalRegisterOperand(regDesp);
1213         SelectCopy(specifiedOpnd, type->GetPrimType(), opnd0, rhsPType);
1214     } else if (memOrd == AArch64isa::kMoNone) {
1215         mOp = PickStInsn(GetPrimTypeBitSize(ptyp), ptyp);
1216         Insn &insn = GetInsnBuilder()->BuildInsn(mOp, stOpnd, *memOpnd);
1217         if (GetCG()->GenerateVerboseCG()) {
1218             insn.SetComment(GenerateMemOpndVerbose(*memOpnd));
1219         }
1220         GetCurBB()->AppendInsn(insn);
1221     } else {
1222         AArch64CGFunc::SelectStoreRelease(*memOpnd, ptyp, stOpnd, ptyp, memOrd, true);
1223     }
1224 }
1225 
SelectDassignoff(DassignoffNode & stmt,Operand & opnd0)1226 void AArch64CGFunc::SelectDassignoff(DassignoffNode &stmt, Operand &opnd0)
1227 {
1228     MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(stmt.stIdx);
1229     int64 offset = stmt.offset;
1230     uint32 size = GetPrimTypeSize(stmt.GetPrimType()) * k8ByteSize;
1231     MOperator mOp = (size == k16BitSize)
1232                         ? MOP_wstrh
1233                         : ((size == k32BitSize) ? MOP_wstr : ((size == k64BitSize) ? MOP_xstr : MOP_undef));
1234     CHECK_FATAL(mOp != MOP_undef, "illegal size for dassignoff");
1235     CHECK_NULL_FATAL(symbol);
1236     MemOperand *memOpnd = &GetOrCreateMemOpnd(*symbol, offset, size);
1237     if ((memOpnd->GetMemVaryType() == kNotVary) &&
1238         (IsImmediateOffsetOutOfRange(*memOpnd, size) || (offset % k8BitSize != 0))) {
1239         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, size);
1240     }
1241     Operand &stOpnd = LoadIntoRegister(opnd0, true, size, false);
1242     memOpnd = memOpnd->IsOffsetMisaligned(size) ? &ConstraintOffsetToSafeRegion(size, *memOpnd, symbol) : memOpnd;
1243     Insn &insn = GetInsnBuilder()->BuildInsn(mOp, stOpnd, *memOpnd);
1244     GetCurBB()->AppendInsn(insn);
1245 }
1246 
SelectAssertNull(UnaryStmtNode & stmt)1247 void AArch64CGFunc::SelectAssertNull(UnaryStmtNode &stmt)
1248 {
1249     Operand *opnd0 = HandleExpr(stmt, *stmt.Opnd(0));
1250     RegOperand &baseReg = LoadIntoRegister(*opnd0, PTY_a64);
1251     auto &zwr = GetZeroOpnd(k32BitSize);
1252     auto &mem = CreateMemOpnd(baseReg, 0, k32BitSize);
1253     Insn &loadRef = GetInsnBuilder()->BuildInsn(MOP_wldr, zwr, mem);
1254     loadRef.SetDoNotRemove(true);
1255     if (GetCG()->GenerateVerboseCG()) {
1256         loadRef.SetComment("null pointer check");
1257     }
1258     GetCurBB()->AppendInsn(loadRef);
1259 }
1260 
SelectAbort()1261 void AArch64CGFunc::SelectAbort()
1262 {
1263     RegOperand &inOpnd = GetOrCreatePhysicalRegisterOperand(R16, k64BitSize, kRegTyInt);
1264     auto &mem = CreateMemOpnd(inOpnd, 0, k64BitSize);
1265     Insn &movXzr = GetInsnBuilder()->BuildInsn(MOP_xmovri64, inOpnd, CreateImmOperand(0, k64BitSize, false));
1266     Insn &loadRef = GetInsnBuilder()->BuildInsn(MOP_wldr, GetZeroOpnd(k64BitSize), mem);
1267     loadRef.SetDoNotRemove(true);
1268     movXzr.SetDoNotRemove(true);
1269     GetCurBB()->AppendInsn(movXzr);
1270     GetCurBB()->AppendInsn(loadRef);
1271     SetCurBBKind(BB::kBBReturn);
1272     GetExitBBsVec().emplace_back(GetCurBB());
1273 }
1274 
GetRegPrefixFromPrimType(PrimType pType,uint32 size,const std::string & constraint)1275 static std::string GetRegPrefixFromPrimType(PrimType pType, uint32 size, const std::string &constraint)
1276 {
1277     std::string regPrefix = "";
1278     /* memory access check */
1279     if (constraint.find("m") != std::string::npos || constraint.find("Q") != std::string::npos) {
1280         regPrefix += "[";
1281     }
1282     if (IsPrimitiveVector(pType)) {
1283         regPrefix += "v";
1284     } else if (IsPrimitiveInteger(pType)) {
1285         if (size == k32BitSize) {
1286             regPrefix += "w";
1287         } else {
1288             regPrefix += "x";
1289         }
1290     } else {
1291         if (size == k32BitSize) {
1292             regPrefix += "s";
1293         } else {
1294             regPrefix += "d";
1295         }
1296     }
1297     return regPrefix;
1298 }
1299 
SelectAsm(AsmNode & node)1300 void AArch64CGFunc::SelectAsm(AsmNode &node)
1301 {
1302     SetHasAsm();
1303     if (Globals::GetInstance()->GetOptimLevel() > CGOptions::kLevel0) {
1304         if (GetCG()->GetCGOptions().DoLinearScanRegisterAllocation()) {
1305             CHECK_FATAL(false, "NIY, lsra unsupported inline asm!");
1306         }
1307     }
1308     Operand *asmString = &CreateStringOperand(node.asmString);
1309     ListOperand *listInputOpnd = CreateListOpnd(*GetFuncScopeAllocator());
1310     ListOperand *listOutputOpnd = CreateListOpnd(*GetFuncScopeAllocator());
1311     ListOperand *listClobber = CreateListOpnd(*GetFuncScopeAllocator());
1312     ListConstraintOperand *listInConstraint = memPool->New<ListConstraintOperand>(*GetFuncScopeAllocator());
1313     ListConstraintOperand *listOutConstraint = memPool->New<ListConstraintOperand>(*GetFuncScopeAllocator());
1314     ListConstraintOperand *listInRegPrefix = memPool->New<ListConstraintOperand>(*GetFuncScopeAllocator());
1315     ListConstraintOperand *listOutRegPrefix = memPool->New<ListConstraintOperand>(*GetFuncScopeAllocator());
1316     std::list<std::pair<Operand *, PrimType>> rPlusOpnd;
1317     bool noReplacement = false;
1318     if (node.asmString.find('$') == std::string::npos) {
1319         /* no replacements */
1320         noReplacement = true;
1321     }
1322     /* input constraints should be processed before OP_asm instruction */
1323     for (size_t i = 0; i < node.numOpnds; ++i) {
1324         /* process input constraint */
1325         std::string str = GlobalTables::GetUStrTable().GetStringFromStrIdx(node.inputConstraints[i]);
1326         bool isOutputTempNode = false;
1327         if (str[0] == '+') {
1328             isOutputTempNode = true;
1329         }
1330         listInConstraint->stringList.push_back(static_cast<StringOperand *>(&CreateStringOperand(str)));
1331         /* process input operands */
1332         switch (node.Opnd(i)->op) {
1333             case OP_dread: {
1334                 DreadNode &dread = static_cast<DreadNode &>(*node.Opnd(i));
1335                 Operand *inOpnd = SelectDread(node, dread);
1336                 PrimType pType = dread.GetPrimType();
1337                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1338                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1339                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1340                 if (isOutputTempNode) {
1341                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1342                 }
1343                 break;
1344             }
1345             case OP_addrof: {
1346                 auto &addrofNode = static_cast<AddrofNode &>(*node.Opnd(i));
1347                 Operand *inOpnd = SelectAddrof(addrofNode, node);
1348                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1349                 PrimType pType = addrofNode.GetPrimType();
1350                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1351                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1352                 if (isOutputTempNode) {
1353                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1354                 }
1355                 break;
1356             }
1357             case OP_addrofoff: {
1358                 auto &addrofoffNode = static_cast<AddrofoffNode &>(*node.Opnd(i));
1359                 Operand *inOpnd = SelectAddrofoff(addrofoffNode, node);
1360                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1361                 PrimType pType = addrofoffNode.GetPrimType();
1362                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1363                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1364                 if (isOutputTempNode) {
1365                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1366                 }
1367                 break;
1368             }
1369             case OP_ireadoff: {
1370                 auto *ireadoff = static_cast<IreadoffNode *>(node.Opnd(i));
1371                 Operand *inOpnd = SelectIreadoff(node, *ireadoff);
1372                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1373                 PrimType pType = ireadoff->GetPrimType();
1374                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1375                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1376                 if (isOutputTempNode) {
1377                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1378                 }
1379                 break;
1380             }
1381             case OP_ireadfpoff: {
1382                 auto *ireadfpoff = static_cast<IreadFPoffNode *>(node.Opnd(i));
1383                 Operand *inOpnd = SelectIreadfpoff(node, *ireadfpoff);
1384                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1385                 PrimType pType = ireadfpoff->GetPrimType();
1386                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1387                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1388                 if (isOutputTempNode) {
1389                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1390                 }
1391                 break;
1392             }
1393             case OP_iread: {
1394                 auto *iread = static_cast<IreadNode *>(node.Opnd(i));
1395                 Operand *inOpnd = SelectIread(node, *iread);
1396                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1397                 PrimType pType = iread->GetPrimType();
1398                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1399                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1400                 if (isOutputTempNode) {
1401                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1402                 }
1403                 break;
1404             }
1405             case OP_add: {
1406                 auto *addNode = static_cast<BinaryNode *>(node.Opnd(i));
1407                 Operand *inOpnd = SelectAdd(*addNode, *HandleExpr(*addNode, *addNode->Opnd(0)),
1408                                             *HandleExpr(*addNode, *addNode->Opnd(1)), node);
1409                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(*inOpnd));
1410                 PrimType pType = addNode->GetPrimType();
1411                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1412                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd->GetSize(), str))));
1413                 if (isOutputTempNode) {
1414                     rPlusOpnd.emplace_back(std::make_pair(inOpnd, pType));
1415                 }
1416                 break;
1417             }
1418 
1419             case OP_constval: {
1420                 CHECK_FATAL(!isOutputTempNode, "Unexpect");
1421                 auto &constNode = static_cast<ConstvalNode &>(*node.Opnd(i));
1422                 CHECK_FATAL(constNode.GetConstVal()->GetKind() == kConstInt,
1423                             "expect MIRIntConst does not support float yet");
1424                 MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(constNode.GetConstVal());
1425                 CHECK_FATAL(mirIntConst != nullptr, "just checking");
1426                 int64 scale = mirIntConst->GetExtValue();
1427                 if (str.find("r") != std::string::npos) {
1428                     bool isSigned = scale < 0;
1429                     ImmOperand &immOpnd = CreateImmOperand(scale, k64BitSize, isSigned);
1430                     /* set default type as a 64 bit reg */
1431                     PrimType pty = isSigned ? PTY_i64 : PTY_u64;
1432                     auto &tempReg = static_cast<Operand &>(CreateRegisterOperandOfType(pty));
1433                     SelectCopy(tempReg, pty, immOpnd, isSigned ? PTY_i64 : PTY_u64);
1434                     listInputOpnd->PushOpnd(static_cast<RegOperand &>(tempReg));
1435                     listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1436                         &CreateStringOperand(GetRegPrefixFromPrimType(pty, tempReg.GetSize(), str))));
1437                 } else {
1438                     RegOperand &inOpnd = GetOrCreatePhysicalRegisterOperand(RZR, k64BitSize, kRegTyInt);
1439                     listInputOpnd->PushOpnd(static_cast<RegOperand &>(inOpnd));
1440 
1441                     listInRegPrefix->stringList.push_back(
1442                         static_cast<StringOperand *>(&CreateStringOperand("i" + std::to_string(scale))));
1443                 }
1444                 break;
1445             }
1446             case OP_regread: {
1447                 auto &regreadNode = static_cast<RegreadNode &>(*node.Opnd(i));
1448                 PregIdx pregIdx = regreadNode.GetRegIdx();
1449                 RegOperand &inOpnd = GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
1450                 listInputOpnd->PushOpnd(static_cast<RegOperand &>(inOpnd));
1451                 MIRPreg *preg = GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
1452                 PrimType pType = preg->GetPrimType();
1453                 listInRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1454                     &CreateStringOperand(GetRegPrefixFromPrimType(pType, inOpnd.GetSize(), str))));
1455                 if (isOutputTempNode) {
1456                     rPlusOpnd.emplace_back(std::make_pair(&static_cast<Operand &>(inOpnd), pType));
1457                 }
1458                 break;
1459             }
1460             default:
1461                 CHECK_FATAL(0, "Inline asm input expression not handled");
1462         }
1463     }
1464     std::vector<Operand *> intrnOpnds;
1465     intrnOpnds.emplace_back(asmString);
1466     intrnOpnds.emplace_back(listOutputOpnd);
1467     intrnOpnds.emplace_back(listClobber);
1468     intrnOpnds.emplace_back(listInputOpnd);
1469     intrnOpnds.emplace_back(listOutConstraint);
1470     intrnOpnds.emplace_back(listInConstraint);
1471     intrnOpnds.emplace_back(listOutRegPrefix);
1472     intrnOpnds.emplace_back(listInRegPrefix);
1473     Insn *asmInsn = &GetInsnBuilder()->BuildInsn(MOP_asm, intrnOpnds);
1474     GetCurBB()->AppendInsn(*asmInsn);
1475 
1476     /* process listOutputOpnd */
1477     for (size_t i = 0; i < node.asmOutputs.size(); ++i) {
1478         bool isOutputTempNode = false;
1479         RegOperand *rPOpnd = nullptr;
1480         /* process output constraint */
1481         std::string str = GlobalTables::GetUStrTable().GetStringFromStrIdx(node.outputConstraints[i]);
1482 
1483         listOutConstraint->stringList.push_back(static_cast<StringOperand *>(&CreateStringOperand(str)));
1484         if (str[0] == '+') {
1485             CHECK_FATAL(!rPlusOpnd.empty(), "Need r+ operand");
1486             rPOpnd = static_cast<RegOperand *>((rPlusOpnd.begin()->first));
1487             listOutputOpnd->PushOpnd(*rPOpnd);
1488             listOutRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1489                 &CreateStringOperand(GetRegPrefixFromPrimType(rPlusOpnd.begin()->second, rPOpnd->GetSize(), str))));
1490             if (!rPlusOpnd.empty()) {
1491                 rPlusOpnd.pop_front();
1492             }
1493             isOutputTempNode = true;
1494         }
1495         if (str.find("Q") != std::string::npos || str.find("m") != std::string::npos) {
1496             continue;
1497         }
1498         /* process output operands */
1499         StIdx stIdx = node.asmOutputs[i].first;
1500         RegFieldPair regFieldPair = node.asmOutputs[i].second;
1501         if (regFieldPair.IsReg()) {
1502             PregIdx pregIdx = static_cast<PregIdx>(regFieldPair.GetPregIdx());
1503             CHECK_NULL_FATAL(mirModule.CurFunction());
1504             MIRPreg *mirPreg = mirModule.CurFunction()->GetPregTab()->PregFromPregIdx(pregIdx);
1505             RegOperand *outOpnd = isOutputTempNode
1506                                       ? rPOpnd
1507                                       : &GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
1508             PrimType srcType = mirPreg->GetPrimType();
1509             PrimType destType = srcType;
1510             if (GetPrimTypeBitSize(destType) < k32BitSize) {
1511                 destType = IsSignedInteger(destType) ? PTY_i32 : PTY_u32;
1512             }
1513             RegType rtype = GetRegTyFromPrimTy(srcType);
1514             RegOperand &opnd0 = isOutputTempNode
1515                                     ? GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx))
1516                                     : CreateVirtualRegisterOperand(NewVReg(rtype, GetPrimTypeSize(srcType)));
1517             SelectCopy(opnd0, destType, *outOpnd, srcType);
1518             if (!isOutputTempNode) {
1519                 listOutputOpnd->PushOpnd(static_cast<RegOperand &>(*outOpnd));
1520                 listOutRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1521                     &CreateStringOperand(GetRegPrefixFromPrimType(srcType, outOpnd->GetSize(), str))));
1522             }
1523         } else {
1524             MIRSymbol *var;
1525             if (stIdx.IsGlobal()) {
1526                 var = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx());
1527             } else {
1528                 CHECK_NULL_FATAL(mirModule.CurFunction());
1529                 var = mirModule.CurFunction()->GetSymbolTabItem(stIdx.Idx());
1530             }
1531             CHECK_FATAL(var != nullptr, "var should not be nullptr");
1532             if (!noReplacement || var->GetAsmAttr() != UStrIdx(0)) {
1533                 RegOperand *outOpnd = nullptr;
1534                 PrimType pty = GlobalTables::GetTypeTable().GetTypeTable().at(var->GetTyIdx())->GetPrimType();
1535                 if (var->GetAsmAttr() != UStrIdx(0)) {
1536                     std::string regDesp = GlobalTables::GetUStrTable().GetStringFromStrIdx(var->GetAsmAttr());
1537                     outOpnd = &GetOrCreatePhysicalRegisterOperand(regDesp);
1538                 } else {
1539                     RegType rtype = GetRegTyFromPrimTy(pty);
1540                     outOpnd =
1541                         isOutputTempNode ? rPOpnd : &CreateVirtualRegisterOperand(NewVReg(rtype, GetPrimTypeSize(pty)));
1542                 }
1543                 SaveReturnValueInLocal(node.asmOutputs, i, PTY_a64, *outOpnd, node);
1544                 if (!isOutputTempNode) {
1545                     listOutputOpnd->PushOpnd(static_cast<RegOperand &>(*outOpnd));
1546                     listOutRegPrefix->stringList.push_back(static_cast<StringOperand *>(
1547                         &CreateStringOperand(GetRegPrefixFromPrimType(pty, outOpnd->GetSize(), str))));
1548                 }
1549             }
1550         }
1551     }
1552     if (noReplacement) {
1553         return;
1554     }
1555 
1556     /* process listClobber */
1557     for (size_t i = 0; i < node.clobberList.size(); ++i) {
1558         std::string str = GlobalTables::GetUStrTable().GetStringFromStrIdx(node.clobberList[i]);
1559         auto regno = static_cast<regno_t>(str[1] - '0');
1560         if (str[2] >= '0' && str[2] <= '9') {  // if third char (index 2) is num, add to regno
1561             regno = regno * kDecimalMax + static_cast<uint32>((str[2] - '0'));
1562         }
1563         RegOperand *reg;
1564         switch (str[0]) {
1565             case 'w': {
1566                 reg = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno + R0), k32BitSize, kRegTyInt);
1567                 listClobber->PushOpnd(*reg);
1568                 break;
1569             }
1570             case 'x': {
1571                 reg = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno + R0), k64BitSize, kRegTyInt);
1572                 listClobber->PushOpnd(*reg);
1573                 break;
1574             }
1575             case 's': {
1576                 reg = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno + V0), k32BitSize, kRegTyFloat);
1577                 listClobber->PushOpnd(*reg);
1578                 break;
1579             }
1580             case 'd': {
1581                 reg = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno + V0), k64BitSize, kRegTyFloat);
1582                 listClobber->PushOpnd(*reg);
1583                 break;
1584             }
1585             case 'v': {
1586                 reg = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno + V0), k64BitSize, kRegTyFloat);
1587                 listClobber->PushOpnd(*reg);
1588                 break;
1589             }
1590             case 'c': {
1591                 asmInsn->SetAsmDefCondCode();
1592                 break;
1593             }
1594             case 'm': {
1595                 asmInsn->SetAsmModMem();
1596                 break;
1597             }
1598             default:
1599                 CHECK_FATAL(0, "Inline asm clobber list not handled");
1600         }
1601     }
1602 }
1603 
SelectRegassign(RegassignNode & stmt,Operand & opnd0)1604 void AArch64CGFunc::SelectRegassign(RegassignNode &stmt, Operand &opnd0)
1605 {
1606     if (GetCG()->IsLmbc()) {
1607         PrimType lhsSize = stmt.GetPrimType();
1608         PrimType rhsSize = stmt.Opnd(0)->GetPrimType();
1609         if (lhsSize != rhsSize && stmt.Opnd(0)->GetOpCode() == OP_ireadoff) {
1610             Insn *prev = GetCurBB()->GetLastMachineInsn();
1611             if (prev && (prev->GetMachineOpcode() == MOP_wldrsb || prev->GetMachineOpcode() == MOP_wldrsh)) {
1612                 opnd0.SetSize(GetPrimTypeBitSize(stmt.GetPrimType()));
1613                 prev->SetMOP(AArch64CG::kMd[prev->GetMachineOpcode() == MOP_wldrsb ? MOP_xldrsb : MOP_xldrsh]);
1614             } else if (prev && (prev->GetMachineOpcode() == MOP_wldr && stmt.GetPrimType() == PTY_i64)) {
1615                 opnd0.SetSize(GetPrimTypeBitSize(stmt.GetPrimType()));
1616                 prev->SetMOP(AArch64CG::kMd[MOP_xldrsw]);
1617             }
1618         }
1619     }
1620     RegOperand *regOpnd = nullptr;
1621     PregIdx pregIdx = stmt.GetRegIdx();
1622     if (IsSpecialPseudoRegister(pregIdx)) {
1623         if (GetCG()->IsLmbc() && stmt.GetPrimType() == PTY_agg) {
1624             if (static_cast<RegOperand &>(opnd0).IsOfIntClass()) {
1625                 regOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, PTY_i64);
1626             } else if (opnd0.GetSize() <= k4ByteSize) {
1627                 regOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, PTY_f32);
1628             } else {
1629                 regOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, PTY_f64);
1630             }
1631         } else {
1632             regOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, stmt.GetPrimType());
1633         }
1634     } else {
1635         regOpnd = &GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
1636     }
1637     /* look at rhs */
1638     PrimType rhsType = stmt.Opnd(0)->GetPrimType();
1639     if (GetCG()->IsLmbc() && rhsType == PTY_agg) {
1640         /* This occurs when a call returns a small struct */
1641         /* The subtree should already taken care of the agg type that is in excess of 8 bytes */
1642         rhsType = PTY_i64;
1643     }
1644     DEBUG_ASSERT(regOpnd != nullptr, "null ptr check!");
1645     Operand *srcOpnd = &opnd0;
1646     if (GetPrimTypeSize(stmt.GetPrimType()) > GetPrimTypeSize(rhsType) && IsPrimitiveInteger(rhsType)) {
1647         CHECK_FATAL(IsPrimitiveInteger(stmt.GetPrimType()), "NIY");
1648         srcOpnd = &CreateRegisterOperandOfType(stmt.GetPrimType());
1649         SelectCvtInt2Int(nullptr, srcOpnd, &opnd0, rhsType, stmt.GetPrimType());
1650     }
1651     SelectCopy(*regOpnd, stmt.GetPrimType(), *srcOpnd, rhsType, stmt.GetRHS());
1652 
1653     if (GetCG()->GenerateVerboseCG()) {
1654         if (GetCurBB()->GetLastInsn()) {
1655             GetCurBB()->GetLastInsn()->AppendComment(" regassign %" + std::to_string(pregIdx) + "; ");
1656         } else if (GetCurBB()->GetPrev()->GetLastInsn()) {
1657             GetCurBB()->GetPrev()->GetLastInsn()->AppendComment(" regassign %" + std::to_string(pregIdx) + "; ");
1658         }
1659     }
1660 
1661     if ((Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) && (pregIdx >= 0)) {
1662         MemOperand *dest = GetPseudoRegisterSpillMemoryOperand(pregIdx);
1663         PrimType stype = GetTypeFromPseudoRegIdx(pregIdx);
1664         MIRPreg *preg = GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
1665         uint32 srcBitLength = GetPrimTypeSize(preg->GetPrimType()) * kBitsPerByte;
1666         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(srcBitLength, stype), *regOpnd, *dest));
1667     } else if (regOpnd->GetRegisterNumber() == R0 || regOpnd->GetRegisterNumber() == R1) {
1668         Insn &pseudo = GetInsnBuilder()->BuildInsn(MOP_pseudo_ret_int, *regOpnd);
1669         GetCurBB()->AppendInsn(pseudo);
1670     } else if (regOpnd->GetRegisterNumber() >= V0 && regOpnd->GetRegisterNumber() <= V3) {
1671         Insn &pseudo = GetInsnBuilder()->BuildInsn(MOP_pseudo_ret_float, *regOpnd);
1672         GetCurBB()->AppendInsn(pseudo);
1673     }
1674     if (stmt.GetPrimType() == PTY_ref) {
1675         regOpnd->SetIsReference(true);
1676         AddReferenceReg(regOpnd->GetRegisterNumber());
1677     }
1678     if (pregIdx > 0) {
1679         // special MIRPreg is not supported
1680         SetPregIdx2Opnd(pregIdx, *regOpnd);
1681     }
1682     const auto &derived2BaseRef = GetFunction().GetDerived2BaseRef();
1683     auto itr = derived2BaseRef.find(pregIdx);
1684     if (itr != derived2BaseRef.end()) {
1685         auto *opnd = GetOpndFromPregIdx(itr->first);
1686         CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
1687         auto &derivedRegOpnd = static_cast<RegOperand &>(*opnd);
1688         opnd = GetOpndFromPregIdx(itr->second);
1689         CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
1690         auto &baseRegOpnd = static_cast<RegOperand &>(*opnd);
1691         derivedRegOpnd.SetBaseRefOpnd(baseRegOpnd);
1692     }
1693 }
1694 
GenFormalMemOpndWithSymbol(const MIRSymbol & sym,int64 offset)1695 MemOperand *AArch64CGFunc::GenFormalMemOpndWithSymbol(const MIRSymbol &sym, int64 offset)
1696 {
1697     MemOperand *memOpnd = nullptr;
1698     if (IsParamStructCopy(sym)) {
1699         memOpnd = &GetOrCreateMemOpnd(sym, 0, k64BitSize);
1700         RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
1701         Insn &ldInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *memOpnd);
1702         GetCurBB()->AppendInsn(ldInsn);
1703         return CreateMemOperand(k64BitSize, *vreg, CreateImmOperand(offset, k32BitSize, false), sym.IsVolatile());
1704     }
1705     return &GetOrCreateMemOpnd(sym, offset, k64BitSize);
1706 }
1707 
FixLargeMemOpnd(MemOperand & memOpnd,uint32 align)1708 MemOperand *AArch64CGFunc::FixLargeMemOpnd(MemOperand &memOpnd, uint32 align)
1709 {
1710     MemOperand *lhsMemOpnd = &memOpnd;
1711     if ((lhsMemOpnd->GetMemVaryType() == kNotVary) && IsImmediateOffsetOutOfRange(*lhsMemOpnd, align * kBitsPerByte)) {
1712         RegOperand *addReg = &CreateRegisterOperandOfType(PTY_i64);
1713         lhsMemOpnd = &SplitOffsetWithAddInstruction(*lhsMemOpnd, align * k8BitSize, addReg->GetRegisterNumber());
1714     }
1715     return lhsMemOpnd;
1716 }
1717 
FixLargeMemOpnd(MOperator mOp,MemOperand & memOpnd,uint32 dSize,uint32 opndIdx)1718 MemOperand *AArch64CGFunc::FixLargeMemOpnd(MOperator mOp, MemOperand &memOpnd, uint32 dSize, uint32 opndIdx)
1719 {
1720     auto *a64MemOpnd = &memOpnd;
1721     if ((a64MemOpnd->GetMemVaryType() == kNotVary) && !IsOperandImmValid(mOp, &memOpnd, opndIdx)) {
1722         if (opndIdx == kInsnSecondOpnd) {
1723             a64MemOpnd = &SplitOffsetWithAddInstruction(*a64MemOpnd, dSize);
1724         } else if (opndIdx == kInsnThirdOpnd) {
1725             a64MemOpnd =
1726                 &SplitOffsetWithAddInstruction(*a64MemOpnd, dSize, AArch64reg::kRinvalid, false, nullptr, true);
1727         } else {
1728             CHECK_FATAL(false, "NYI");
1729         }
1730     }
1731     return a64MemOpnd;
1732 }
1733 
GenLargeAggFormalMemOpnd(const MIRSymbol & sym,uint32 align,int64 offset,bool needLow12)1734 MemOperand *AArch64CGFunc::GenLargeAggFormalMemOpnd(const MIRSymbol &sym, uint32 align, int64 offset, bool needLow12)
1735 {
1736     MemOperand *memOpnd;
1737     if (sym.GetStorageClass() == kScFormal && GetBecommon().GetTypeSize(sym.GetTyIdx()) > k16ByteSize) {
1738         /* formal of size of greater than 16 is copied by the caller and the pointer to it is passed. */
1739         /* otherwise it is passed in register and is accessed directly. */
1740         memOpnd = &GetOrCreateMemOpnd(sym, 0, align * kBitsPerByte);
1741         RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
1742         Insn &ldInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *memOpnd);
1743         GetCurBB()->AppendInsn(ldInsn);
1744         memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, vreg, nullptr,
1745                                       &GetOrCreateOfstOpnd(static_cast<uint64>(offset), k32BitSize), nullptr);
1746     } else {
1747         memOpnd = &GetOrCreateMemOpnd(sym, offset, align * kBitsPerByte, false, needLow12);
1748     }
1749     return FixLargeMemOpnd(*memOpnd, align);
1750 }
1751 
PrepareMemcpyParamOpnd(bool isLo12,const MIRSymbol & symbol,int64 offsetVal,RegOperand & BaseReg)1752 RegOperand *AArch64CGFunc::PrepareMemcpyParamOpnd(bool isLo12, const MIRSymbol &symbol, int64 offsetVal,
1753                                                   RegOperand &BaseReg)
1754 {
1755     RegOperand *tgtAddr = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
1756     if (isLo12) {
1757         StImmOperand &stImm = CreateStImmOperand(symbol, 0, 0);
1758         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, *tgtAddr, BaseReg, stImm));
1759     } else {
1760         ImmOperand &imm = CreateImmOperand(offsetVal, k64BitSize, false);
1761         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *tgtAddr, BaseReg, imm));
1762     }
1763     return tgtAddr;
1764 }
1765 
PrepareMemcpyParamOpnd(int64 offset,Operand & exprOpnd)1766 RegOperand *AArch64CGFunc::PrepareMemcpyParamOpnd(int64 offset, Operand &exprOpnd)
1767 {
1768     RegOperand *tgtAddr = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
1769     OfstOperand *ofstOpnd = &GetOrCreateOfstOpnd(static_cast<uint64>(offset), k32BitSize);
1770     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *tgtAddr, exprOpnd, *ofstOpnd));
1771     return tgtAddr;
1772 }
1773 
PrepareMemcpyParamOpnd(uint64 copySize)1774 RegOperand *AArch64CGFunc::PrepareMemcpyParamOpnd(uint64 copySize)
1775 {
1776     RegOperand *vregMemcpySize = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
1777     ImmOperand *sizeOpnd = &CreateImmOperand(static_cast<int64>(copySize), k64BitSize, false);
1778     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, *vregMemcpySize, *sizeOpnd));
1779     return vregMemcpySize;
1780 }
1781 
AggtStrLdrInsert(bool bothUnion,Insn * lastStrLdr,Insn & newStrLdr)1782 Insn *AArch64CGFunc::AggtStrLdrInsert(bool bothUnion, Insn *lastStrLdr, Insn &newStrLdr)
1783 {
1784     if (bothUnion) {
1785         if (lastStrLdr == nullptr) {
1786             GetCurBB()->AppendInsn(newStrLdr);
1787         } else {
1788             GetCurBB()->InsertInsnAfter(*lastStrLdr, newStrLdr);
1789         }
1790     } else {
1791         GetCurBB()->AppendInsn(newStrLdr);
1792     }
1793     return &newStrLdr;
1794 }
1795 
SelectRhsMemOpnd(BaseNode & rhsStmt,bool & isRefField)1796 MemOperand *AArch64CGFunc::SelectRhsMemOpnd(BaseNode &rhsStmt, bool &isRefField)
1797 {
1798     MemOperand *rhsMemOpnd = nullptr;
1799     if (rhsStmt.GetOpCode() == OP_dread) {
1800         MemRWNodeHelper rhsMemHelper(rhsStmt, GetFunction(), GetBecommon());
1801         auto *rhsSymbol = rhsMemHelper.GetSymbol();
1802         rhsMemOpnd = GenFormalMemOpndWithSymbol(*rhsSymbol, rhsMemHelper.GetByteOffset());
1803         isRefField = rhsMemHelper.IsRefField();
1804     } else {
1805         DEBUG_ASSERT(rhsStmt.GetOpCode() == OP_iread, "SelectRhsMemOpnd: NYI");
1806         auto &rhsIread = static_cast<IreadNode &>(rhsStmt);
1807         MemRWNodeHelper rhsMemHelper(rhsIread, GetFunction(), GetBecommon());
1808         auto *rhsAddrOpnd = HandleExpr(rhsIread, *rhsIread.Opnd(0));
1809         auto &rhsAddr = LoadIntoRegister(*rhsAddrOpnd, rhsIread.Opnd(0)->GetPrimType());
1810         auto &rhsOfstOpnd = CreateImmOperand(rhsMemHelper.GetByteOffset(), k32BitSize, false);
1811         rhsMemOpnd = CreateMemOperand(k64BitSize, rhsAddr, rhsOfstOpnd, rhsIread.IsVolatile());
1812         isRefField = rhsMemHelper.IsRefField();
1813     }
1814     return rhsMemOpnd;
1815 }
1816 
SelectRhsMemOpnd(BaseNode & rhsStmt)1817 MemOperand *AArch64CGFunc::SelectRhsMemOpnd(BaseNode &rhsStmt)
1818 {
1819     bool isRefField = false;
1820     return SelectRhsMemOpnd(rhsStmt, isRefField);
1821 }
1822 
GetOrCreateLocator(CallConvKind cc)1823 CCImpl *AArch64CGFunc::GetOrCreateLocator(CallConvKind cc)
1824 {
1825     auto it = hashCCTable.find(cc);
1826     if (it != hashCCTable.end()) {
1827         it->second->Init();
1828         return it->second;
1829     }
1830     CCImpl *res = nullptr;
1831     if (cc == kCCall) {
1832         res = memPool->New<AArch64CallConvImpl>(GetBecommon());
1833     } else if (cc == kWebKitJS) {
1834         res = memPool->New<AArch64WebKitJSCC>(GetBecommon());
1835     } else if (cc == kGHC) {
1836         res = memPool->New<GHCCC>(GetBecommon());
1837     } else {
1838         CHECK_FATAL(false, "unsupported yet");
1839     }
1840     hashCCTable[cc] = res;
1841     return res;
1842 }
SelectAggDassign(DassignNode & stmt)1843 void AArch64CGFunc::SelectAggDassign(DassignNode &stmt)
1844 {
1845     DEBUG_ASSERT(stmt.Opnd(0) != nullptr, "null ptr check");
1846     MemRWNodeHelper lhsMemHelper(stmt, GetFunction(), GetBecommon());
1847     auto *lhsSymbol = lhsMemHelper.GetSymbol();
1848     DEBUG_ASSERT(lhsSymbol != nullptr, "nullptr check");
1849     auto *lhsMemOpnd = GenFormalMemOpndWithSymbol(*lhsSymbol, lhsMemHelper.GetByteOffset());
1850 
1851     bool isRefField = false;
1852     auto *rhsMemOpnd = SelectRhsMemOpnd(*stmt.GetRHS(), isRefField);
1853     SelectMemCopy(*lhsMemOpnd, *rhsMemOpnd, lhsMemHelper.GetMemSize(), isRefField, &stmt, stmt.GetRHS());
1854 }
1855 
GetPointedToType(const MIRPtrType & pointerType)1856 static MIRType *GetPointedToType(const MIRPtrType &pointerType)
1857 {
1858     MIRType *aType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType.GetPointedTyIdx());
1859     if (aType->GetKind() == kTypeArray) {
1860         MIRArrayType *arrayType = static_cast<MIRArrayType *>(aType);
1861         return GlobalTables::GetTypeTable().GetTypeFromTyIdx(arrayType->GetElemTyIdx());
1862     }
1863     if (aType->GetKind() == kTypeFArray || aType->GetKind() == kTypeJArray) {
1864         MIRFarrayType *farrayType = static_cast<MIRFarrayType *>(aType);
1865         return GlobalTables::GetTypeTable().GetTypeFromTyIdx(farrayType->GetElemTyIdx());
1866     }
1867     return aType;
1868 }
1869 
SelectIassign(IassignNode & stmt)1870 void AArch64CGFunc::SelectIassign(IassignNode &stmt)
1871 {
1872     int32 offset = 0;
1873     MIRPtrType *pointerType = static_cast<MIRPtrType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(stmt.GetTyIdx()));
1874     DEBUG_ASSERT(pointerType != nullptr, "expect a pointer type at iassign node");
1875     MIRType *pointedType = nullptr;
1876     bool isRefField = false;
1877     AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone;
1878 
1879     if (stmt.GetFieldID() != 0) {
1880         MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx());
1881         MIRStructType *structType = nullptr;
1882         if (pointedTy->GetKind() != kTypeJArray) {
1883             structType = static_cast<MIRStructType *>(pointedTy);
1884         } else {
1885             structType = static_cast<MIRJarrayType *>(pointedTy)->GetParentType();
1886         }
1887         DEBUG_ASSERT(structType != nullptr, "SelectIassign: non-zero fieldID for non-structure");
1888         pointedType = structType->GetFieldType(stmt.GetFieldID());
1889         offset = GetBecommon().GetFieldOffset(*structType, stmt.GetFieldID()).first;
1890         isRefField = GetBecommon().IsRefField(*structType, stmt.GetFieldID());
1891     } else {
1892         pointedType = GetPointedToType(*pointerType);
1893     }
1894 
1895     PrimType styp = stmt.GetRHS()->GetPrimType();
1896     Operand *valOpnd = HandleExpr(stmt, *stmt.GetRHS());
1897     Operand &srcOpnd = LoadIntoRegister(*valOpnd, (IsPrimitiveInteger(styp) || IsPrimitiveVectorInteger(styp)),
1898                                         GetPrimTypeBitSize(styp));
1899 
1900     PrimType destType = pointedType->GetPrimType();
1901     if (destType == PTY_agg) {
1902         destType = PTY_a64;
1903     }
1904     if (IsPrimitiveVector(styp)) { /* a vector type */
1905         destType = styp;
1906     }
1907     DEBUG_ASSERT(stmt.Opnd(0) != nullptr, "null ptr check");
1908     MemOperand &memOpnd = CreateMemOpnd(destType, stmt, *stmt.Opnd(0), offset);
1909     auto dataSize = GetPrimTypeBitSize(destType);
1910     memOpnd = memOpnd.IsOffsetMisaligned(dataSize) ? ConstraintOffsetToSafeRegion(dataSize, memOpnd, nullptr) : memOpnd;
1911     if (isVolStore && memOpnd.GetAddrMode() == MemOperand::kAddrModeBOi) {
1912         memOrd = AArch64isa::kMoRelease;
1913         isVolStore = false;
1914     }
1915 
1916     if (memOrd == AArch64isa::kMoNone) {
1917         SelectCopy(memOpnd, destType, srcOpnd, destType);
1918     } else {
1919         AArch64CGFunc::SelectStoreRelease(memOpnd, destType, srcOpnd, destType, memOrd, false);
1920     }
1921     if (GetCurBB() && GetCurBB()->GetLastMachineInsn()) {
1922         GetCurBB()->GetLastMachineInsn()->MarkAsAccessRefField(isRefField);
1923     }
1924 }
1925 
SelectIassignoff(IassignoffNode & stmt)1926 void AArch64CGFunc::SelectIassignoff(IassignoffNode &stmt)
1927 {
1928     int32 offset = stmt.GetOffset();
1929     PrimType destType = stmt.GetPrimType();
1930 
1931     MemOperand &memOpnd = CreateMemOpnd(destType, stmt, *stmt.GetBOpnd(0), offset);
1932     auto dataSize = GetPrimTypeBitSize(destType);
1933     memOpnd = memOpnd.IsOffsetMisaligned(dataSize) ? ConstraintOffsetToSafeRegion(dataSize, memOpnd, nullptr) : memOpnd;
1934     Operand *valOpnd = HandleExpr(stmt, *stmt.GetBOpnd(1));
1935     Operand &srcOpnd = LoadIntoRegister(*valOpnd, true, GetPrimTypeBitSize(destType));
1936     SelectCopy(memOpnd, destType, srcOpnd, destType);
1937 }
1938 
GenLmbcFpMemOperand(int32 offset,uint32 byteSize,AArch64reg baseRegno)1939 MemOperand *AArch64CGFunc::GenLmbcFpMemOperand(int32 offset, uint32 byteSize, AArch64reg baseRegno)
1940 {
1941     MemOperand *memOpnd;
1942     RegOperand *rfp = &GetOrCreatePhysicalRegisterOperand(baseRegno, k64BitSize, kRegTyInt);
1943     uint32 bitlen = byteSize * kBitsPerByte;
1944     if (offset < 0 && offset < kNegative256BitSize) {
1945         RegOperand *baseOpnd = &CreateRegisterOperandOfType(PTY_a64);
1946         ImmOperand &immOpnd = CreateImmOperand(offset, k32BitSize, true);
1947         Insn &addInsn = GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *baseOpnd, *rfp, immOpnd);
1948         GetCurBB()->AppendInsn(addInsn);
1949         OfstOperand *offsetOpnd = &CreateOfstOpnd(0, k32BitSize);
1950         memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, bitlen, baseOpnd, nullptr, offsetOpnd, nullptr);
1951     } else {
1952         OfstOperand *offsetOpnd = &CreateOfstOpnd(static_cast<uint64>(static_cast<int64>(offset)), k32BitSize);
1953         memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, bitlen, rfp, nullptr, offsetOpnd, nullptr);
1954     }
1955     memOpnd->SetStackMem(true);
1956     return memOpnd;
1957 }
1958 
SelectIassignfpoff(IassignFPoffNode & stmt,Operand & opnd)1959 void AArch64CGFunc::SelectIassignfpoff(IassignFPoffNode &stmt, Operand &opnd)
1960 {
1961     int32 offset = stmt.GetOffset();
1962     PrimType primType = stmt.GetPrimType();
1963     MIRType *rType = GetLmbcCallReturnType();
1964     bool isPureFpStruct = false;
1965     uint32 numRegs = 0;
1966     if (rType && rType->GetPrimType() == PTY_agg && opnd.IsRegister() &&
1967         static_cast<RegOperand &>(opnd).IsPhysicalRegister()) {
1968         CHECK_FATAL(rType->GetSize() <= k16BitSize, "SelectIassignfpoff invalid agg size");
1969         uint32 fpSize;
1970         numRegs = FloatParamRegRequired(static_cast<MIRStructType *>(rType), fpSize);
1971         if (numRegs) {
1972             primType = (fpSize == k4ByteSize) ? PTY_f32 : PTY_f64;
1973             isPureFpStruct = true;
1974         }
1975     }
1976     uint32 byteSize = GetPrimTypeSize(primType);
1977     uint32 bitlen = byteSize * kBitsPerByte;
1978     if (isPureFpStruct) {
1979         for (uint32 i = 0; i < numRegs; ++i) {
1980             MemOperand *memOpnd = GenLmbcFpMemOperand(offset + static_cast<int32>(i * byteSize), byteSize);
1981             RegOperand &srcOpnd = GetOrCreatePhysicalRegisterOperand(AArch64reg(V0 + i), bitlen, kRegTyFloat);
1982             MOperator mOp = PickStInsn(bitlen, primType);
1983             Insn &store = GetInsnBuilder()->BuildInsn(mOp, srcOpnd, *memOpnd);
1984             GetCurBB()->AppendInsn(store);
1985         }
1986     } else {
1987         Operand &srcOpnd = LoadIntoRegister(opnd, primType);
1988         MemOperand *memOpnd = GenLmbcFpMemOperand(offset, byteSize);
1989         MOperator mOp = PickStInsn(bitlen, primType);
1990         Insn &store = GetInsnBuilder()->BuildInsn(mOp, srcOpnd, *memOpnd);
1991         GetCurBB()->AppendInsn(store);
1992     }
1993 }
1994 
1995 /* Load and assign to a new register. To be moved to the correct call register OR stack
1996    location in LmbcSelectParmList */
SelectIassignspoff(PrimType pTy,int32 offset,Operand & opnd)1997 void AArch64CGFunc::SelectIassignspoff(PrimType pTy, int32 offset, Operand &opnd)
1998 {
1999     if (GetLmbcArgInfo() == nullptr) {
2000         LmbcArgInfo *p = memPool->New<LmbcArgInfo>(*GetFuncScopeAllocator());
2001         SetLmbcArgInfo(p);
2002     }
2003     uint32 byteLen = GetPrimTypeSize(pTy);
2004     uint32 bitLen = byteLen * kBitsPerByte;
2005     RegType regTy = GetRegTyFromPrimTy(pTy);
2006     int32 curRegArgs = GetLmbcArgsInRegs(regTy);
2007     if (curRegArgs < static_cast<int32>(k8ByteSize)) {
2008         RegOperand *res = &CreateVirtualRegisterOperand(NewVReg(regTy, byteLen));
2009         SelectCopy(*res, pTy, opnd, pTy);
2010         SetLmbcArgInfo(res, pTy, offset, 1);
2011     } else {
2012         /* Move into allocated space */
2013         Operand &memOpd = CreateMemOpnd(RSP, offset, byteLen);
2014         Operand &reg = LoadIntoRegister(opnd, pTy);
2015         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(bitLen, pTy), reg, memOpd));
2016     }
2017     IncLmbcArgsInRegs(regTy); /* num of args in registers */
2018     IncLmbcTotalArgs();       /* num of args */
2019 }
2020 
2021 /* Search for CALL/ICALL/ICALLPROTO node, must be called from a blkassignoff node */
LmbcGetAggTyFromCallSite(StmtNode * stmt,std::vector<TyIdx> ** parmList) const2022 MIRType *AArch64CGFunc::LmbcGetAggTyFromCallSite(StmtNode *stmt, std::vector<TyIdx> **parmList) const
2023 {
2024     for (; stmt != nullptr; stmt = stmt->GetNext()) {
2025         if (stmt->GetOpCode() == OP_call || stmt->GetOpCode() == OP_icallproto) {
2026             break;
2027         }
2028     }
2029     CHECK_FATAL(stmt && (stmt->GetOpCode() == OP_call || stmt->GetOpCode() == OP_icallproto),
2030                 "blkassign sp not followed by call");
2031     uint32 nargs = GetLmbcTotalArgs();
2032     MIRType *ty = nullptr;
2033     if (stmt->GetOpCode() == OP_call) {
2034         CallNode *callNode = static_cast<CallNode *>(stmt);
2035         MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx());
2036         if (fn->GetFormalCount() > 0) {
2037             ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fn->GetFormalDefVec()[nargs].formalTyIdx);
2038         }
2039         *parmList = &fn->GetParamTypes();
2040         // would return null if the actual parameter is bogus
2041     } else if (stmt->GetOpCode() == OP_icallproto) {
2042         IcallNode *icallproto = static_cast<IcallNode *>(stmt);
2043         MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(icallproto->GetRetTyIdx());
2044         MIRFuncType *fType = static_cast<MIRFuncType *>(type);
2045         ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fType->GetNthParamType(nargs));
2046         *parmList = &fType->GetParamTypeList();
2047     } else {
2048         CHECK_FATAL(stmt->GetOpCode() == OP_icallproto, "LmbcGetAggTyFromCallSite:: unexpected call operator");
2049     }
2050     return ty;
2051 }
2052 
2053 /* return true if blkassignoff for return, false otherwise */
LmbcSmallAggForRet(const BaseNode & bNode,const Operand * src,int32 offset,bool skip1)2054 bool AArch64CGFunc::LmbcSmallAggForRet(const BaseNode &bNode, const Operand *src, int32 offset, bool skip1)
2055 {
2056     PrimType pTy;
2057     uint32 size = 0;
2058     AArch64reg regno = static_cast<AArch64reg>(static_cast<const RegOperand *>(src)->GetRegisterNumber());
2059     MIRFunction *func = &GetFunction();
2060 
2061     if (!func->IsReturnStruct()) {
2062         return false;
2063     }
2064     /* This blkassignoff is for struct return? */
2065     uint32 loadSize;
2066     uint32 numRegs = 0;
2067     if (static_cast<const StmtNode &>(bNode).GetNext()->GetOpCode() == OP_return) {
2068         MIRStructType *ty = static_cast<MIRStructType *>(func->GetReturnType());
2069         uint32 tySize = GetBecommon().GetTypeSize(ty->GetTypeIndex());
2070         uint32 fpregs = FloatParamRegRequired(ty, size);
2071         if (fpregs > 0) {
2072             /* pure floating point in agg */
2073             numRegs = fpregs;
2074             pTy = (size == k4ByteSize) ? PTY_f32 : PTY_f64;
2075             loadSize = GetPrimTypeSize(pTy) * kBitsPerByte;
2076             for (uint32 i = 0; i < fpregs; i++) {
2077                 int32 s = (i == 0) ? 0 : static_cast<int32>(i * size);
2078                 int64 newOffset = static_cast<int64>(s) + static_cast<int64>(offset);
2079                 MemOperand &mem = CreateMemOpnd(regno, newOffset, size * kBitsPerByte);
2080                 AArch64reg reg = static_cast<AArch64reg>(V0 + i);
2081                 RegOperand *res = &GetOrCreatePhysicalRegisterOperand(reg, loadSize, kRegTyFloat);
2082                 SelectCopy(*res, pTy, mem, pTy);
2083             }
2084         } else {
2085             constexpr uint8 numRegMax = 2;
2086             /* int/float mixed */
2087             numRegs = numRegMax;
2088             pTy = PTY_i64;
2089             constexpr uint32 oneByte = 1;
2090             constexpr uint32 twoByte = 2;
2091             constexpr uint32 fourByte = 4;
2092             size = k4ByteSize;
2093             switch (tySize) {
2094                 case oneByte:
2095                     pTy = PTY_i8;
2096                     break;
2097                 case twoByte:
2098                     pTy = PTY_i16;
2099                     break;
2100                 case fourByte:
2101                     pTy = PTY_i32;
2102                     break;
2103                 default:
2104                     size = k8ByteSize; /* pTy remains i64 */
2105                     break;
2106             }
2107             loadSize = GetPrimTypeSize(pTy) * kBitsPerByte;
2108             if (!skip1) {
2109                 MemOperand &mem = CreateMemOpnd(regno, offset, size * kBitsPerByte);
2110                 RegOperand &res1 = GetOrCreatePhysicalRegisterOperand(R0, loadSize, kRegTyInt);
2111                 SelectCopy(res1, pTy, mem, pTy);
2112             }
2113             if (tySize > k8ByteSize) {
2114                 int32 newOffset = offset + static_cast<int32>(k8ByteSize);
2115                 MemOperand &newMem = CreateMemOpnd(regno, newOffset, size * kBitsPerByte);
2116                 RegOperand &res2 = GetOrCreatePhysicalRegisterOperand(R1, loadSize, kRegTyInt);
2117                 SelectCopy(res2, pTy, newMem, pTy);
2118             }
2119         }
2120         bool intReg = fpregs == 0;
2121         for (uint32 i = 0; i < numRegs; i++) {
2122             AArch64reg preg = static_cast<AArch64reg>((intReg ? R0 : V0) + i);
2123             MOperator mop = intReg ? MOP_pseudo_ret_int : MOP_pseudo_ret_float;
2124             RegOperand &dest = GetOrCreatePhysicalRegisterOperand(preg, loadSize, intReg ? kRegTyInt : kRegTyFloat);
2125             Insn &pseudo = GetInsnBuilder()->BuildInsn(mop, dest);
2126             GetCurBB()->AppendInsn(pseudo);
2127         }
2128         return true;
2129     }
2130     return false;
2131 }
2132 
2133 /* return true if blkassignoff for return, false otherwise */
LmbcSmallAggForCall(BlkassignoffNode & bNode,const Operand * src,std::vector<TyIdx> ** parmList)2134 bool AArch64CGFunc::LmbcSmallAggForCall(BlkassignoffNode &bNode, const Operand *src, std::vector<TyIdx> **parmList)
2135 {
2136     AArch64reg regno = static_cast<AArch64reg>(static_cast<const RegOperand *>(src)->GetRegisterNumber());
2137     if (IsBlkassignForPush(bNode)) {
2138         PrimType pTy = PTY_i64;
2139         MIRStructType *ty = static_cast<MIRStructType *>(LmbcGetAggTyFromCallSite(&bNode, parmList));
2140         uint32 size = 0;
2141         uint32 fpregs = ty ? FloatParamRegRequired(ty, size) : 0; /* fp size determined */
2142         if (fpregs > 0) {
2143             /* pure floating point in agg */
2144             pTy = (size == k4ByteSize) ? PTY_f32 : PTY_f64;
2145             for (uint32 i = 0; i < fpregs; i++) {
2146                 int32 s = (i == 0) ? 0 : static_cast<int32>(i * size);
2147                 MemOperand &mem = CreateMemOpnd(regno, s, size * kBitsPerByte);
2148                 RegOperand *res = &CreateVirtualRegisterOperand(NewVReg(kRegTyFloat, size));
2149                 SelectCopy(*res, pTy, mem, pTy);
2150                 SetLmbcArgInfo(res, pTy, 0, static_cast<int32>(fpregs));
2151                 IncLmbcArgsInRegs(kRegTyFloat);
2152             }
2153             IncLmbcTotalArgs();
2154             return true;
2155         } else if (bNode.blockSize <= static_cast<int32>(k16ByteSize)) {
2156             /* integer/mixed types in register/s */
2157             size = k4ByteSize;
2158             switch (bNode.blockSize) {
2159                 case k1ByteSize:
2160                     pTy = PTY_i8;
2161                     break;
2162                 case k2ByteSize:
2163                     pTy = PTY_i16;
2164                     break;
2165                 case k4ByteSize:
2166                     pTy = PTY_i32;
2167                     break;
2168                 default:
2169                     size = k8ByteSize; /* pTy remains i64 */
2170                     break;
2171             }
2172             MemOperand &mem = CreateMemOpnd(regno, 0, size * kBitsPerByte);
2173             RegOperand *res = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, size));
2174             SelectCopy(*res, pTy, mem, pTy);
2175             SetLmbcArgInfo(res, pTy, bNode.offset,
2176                            bNode.blockSize > static_cast<int32>(k8ByteSize) ? kThirdReg : kSecondReg);
2177             IncLmbcArgsInRegs(kRegTyInt);
2178             if (bNode.blockSize > static_cast<int32>(k8ByteSize)) {
2179                 MemOperand &newMem = CreateMemOpnd(regno, k8ByteSize, size * kBitsPerByte);
2180                 RegOperand *newRes = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, size));
2181                 SelectCopy(*newRes, pTy, newMem, pTy);
2182                 SetLmbcArgInfo(newRes, pTy, bNode.offset + k8ByteSizeInt, kThirdReg);
2183                 IncLmbcArgsInRegs(kRegTyInt);
2184             }
2185             IncLmbcTotalArgs();
2186             return true;
2187         }
2188     }
2189     return false;
2190 }
2191 
2192 /* This function is incomplete and may be removed when Lmbc IR is changed
2193    to have the lowerer figures out the address of the large agg to reside */
LmbcFindTotalStkUsed(std::vector<TyIdx> * paramList)2194 uint32 AArch64CGFunc::LmbcFindTotalStkUsed(std::vector<TyIdx> *paramList)
2195 {
2196     AArch64CallConvImpl parmlocator(GetBecommon());
2197     CCLocInfo pLoc;
2198     for (TyIdx tyIdx : *paramList) {
2199         MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
2200         (void)parmlocator.LocateNextParm(*ty, pLoc);
2201     }
2202     return 0;
2203 }
2204 
2205 /* All arguments passed as registers */
LmbcTotalRegsUsed()2206 uint32 AArch64CGFunc::LmbcTotalRegsUsed()
2207 {
2208     if (GetLmbcArgInfo() == nullptr) {
2209         return 0; /* no arg */
2210     }
2211     MapleVector<int32> &regs = GetLmbcCallArgNumOfRegs();
2212     MapleVector<PrimType> &types = GetLmbcCallArgTypes();
2213     uint32 iCnt = 0;
2214     uint32 fCnt = 0;
2215     for (uint32 i = 0; i < regs.size(); i++) {
2216         if (IsPrimitiveInteger(types[i])) {
2217             if ((iCnt + static_cast<uint32>(regs[i])) <= k8ByteSize) {
2218                 iCnt += static_cast<uint32>(regs[i]);
2219             };
2220         } else {
2221             if ((fCnt + static_cast<uint32>(regs[i])) <= k8ByteSize) {
2222                 fCnt += static_cast<uint32>(regs[i]);
2223             };
2224         }
2225     }
2226     return iCnt + fCnt;
2227 }
2228 
2229 /* If blkassignoff for argument, this function loads the agg arguments into
2230    virtual registers, disregard if there is sufficient physicall call
2231    registers. Argument > 16-bytes are copied to preset space and ptr
2232    result is loaded into virtual register.
2233    If blassign is not for argument, this function simply memcpy */
SelectBlkassignoff(BlkassignoffNode & bNode,Operand * src)2234 void AArch64CGFunc::SelectBlkassignoff(BlkassignoffNode &bNode, Operand *src)
2235 {
2236     CHECK_FATAL(src->GetKind() == Operand::kOpdRegister, "blkassign src type not in register");
2237     std::vector<TyIdx> *parmList;
2238     if (GetLmbcArgInfo() == nullptr) {
2239         LmbcArgInfo *p = memPool->New<LmbcArgInfo>(*GetFuncScopeAllocator());
2240         SetLmbcArgInfo(p);
2241     }
2242     if (LmbcSmallAggForRet(bNode, src)) {
2243         return;
2244     } else if (LmbcSmallAggForCall(bNode, src, &parmList)) {
2245         return;
2246     }
2247     Operand *dest = HandleExpr(bNode, *bNode.Opnd(0));
2248     RegOperand *regResult = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
2249     /* memcpy for agg assign OR large agg for arg/ret */
2250     int32 offset = bNode.offset;
2251     if (IsBlkassignForPush(bNode)) {
2252         /* large agg for call, addr to be pushed in SelectCall */
2253         offset = GetLmbcTotalStkUsed();
2254         if (offset < 0) {
2255             /* length of ALL stack based args for this call, this location is where the
2256                next large agg resides, its addr will then be passed */
2257             offset = static_cast<int32_t>(LmbcFindTotalStkUsed(parmList) + LmbcTotalRegsUsed());
2258         }
2259         SetLmbcTotalStkUsed(offset + bNode.blockSize); /* next use */
2260         SetLmbcArgInfo(regResult, PTY_i64, 0, 1);      /* 1 reg for ptr */
2261         IncLmbcArgsInRegs(kRegTyInt);
2262         IncLmbcTotalArgs();
2263         /* copy large agg arg to offset below */
2264     }
2265     std::vector<Operand *> opndVec;
2266     opndVec.push_back(regResult);                                                                        /* result */
2267     opndVec.push_back(PrepareMemcpyParamOpnd(offset, *dest));                                            /* param 0 */
2268     opndVec.push_back(src);                                                                              /* param 1 */
2269     opndVec.push_back(PrepareMemcpyParamOpnd(static_cast<uint64>(static_cast<int64>(bNode.blockSize)))); /* param 2 */
2270     SelectLibCall("memcpy", opndVec, PTY_a64, PTY_a64);
2271 }
2272 
SelectAggIassign(IassignNode & stmt,Operand & addrOpnd)2273 void AArch64CGFunc::SelectAggIassign(IassignNode &stmt, Operand &addrOpnd)
2274 {
2275     DEBUG_ASSERT(stmt.Opnd(0) != nullptr, "null ptr check");
2276     auto &lhsAddrOpnd = LoadIntoRegister(addrOpnd, stmt.Opnd(0)->GetPrimType());
2277     MemRWNodeHelper lhsMemHelper(stmt, GetFunction(), GetBecommon());
2278     auto &lhsOfstOpnd = CreateImmOperand(lhsMemHelper.GetByteOffset(), k32BitSize, false);
2279     auto *lhsMemOpnd = CreateMemOperand(k64BitSize, lhsAddrOpnd, lhsOfstOpnd, stmt.AssigningVolatile());
2280 
2281     bool isRefField = false;
2282     MemOperand *rhsMemOpnd = SelectRhsMemOpnd(*stmt.GetRHS(), isRefField);
2283     SelectMemCopy(*lhsMemOpnd, *rhsMemOpnd, lhsMemHelper.GetMemSize(), isRefField, &stmt, stmt.GetRHS());
2284 }
2285 
SelectReturnSendOfStructInRegs(BaseNode * x)2286 void AArch64CGFunc::SelectReturnSendOfStructInRegs(BaseNode *x)
2287 {
2288     if (x->GetOpCode() != OP_dread && x->GetOpCode() != OP_iread) {
2289         // dummy return of 0 inserted by front-end at absence of return
2290         DEBUG_ASSERT(x->GetOpCode() == OP_constval, "NIY: unexpected return operand");
2291         uint32 typeSize = GetPrimTypeBitSize(x->GetPrimType());
2292         RegOperand &dest = GetOrCreatePhysicalRegisterOperand(R0, typeSize, kRegTyInt);
2293         ImmOperand &src = CreateImmOperand(0, typeSize, false);
2294         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, dest, src));
2295         return;
2296     }
2297 
2298     MemRWNodeHelper helper(*x, GetFunction(), GetBecommon());
2299     bool isRefField = false;
2300     auto *addrOpnd = SelectRhsMemOpnd(*x, isRefField);
2301 
2302     // generate move to regs for agg return
2303     AArch64CallConvImpl parmlocator(GetBecommon());
2304     CCLocInfo retMatch;
2305     parmlocator.LocateRetVal(*helper.GetMIRType(), retMatch);
2306     if (retMatch.GetReg0() == kRinvalid) {
2307         return;
2308     }
2309 
2310     uint32 offset = 0;
2311     std::vector<RegOperand *> result;
2312     // load memOpnd to return reg
2313     // ldr x0, [base]
2314     // ldr x1, [base + 8]
2315     auto generateReturnValToRegs = [this, &result, &offset, isRefField, &addrOpnd](regno_t regno, PrimType primType) {
2316         bool isFpReg = IsPrimitiveFloat(primType) || IsPrimitiveVector(primType);
2317         RegType regType = isFpReg ? kRegTyFloat : kRegTyInt;
2318         if (CGOptions::IsBigEndian() && !isFpReg) {
2319             primType = PTY_u64;
2320         } else if (GetPrimTypeSize(primType) <= k4ByteSize) {
2321             primType = isFpReg ? PTY_f32 : PTY_u32;
2322         }
2323         auto &phyReg =
2324             GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(regno), GetPrimTypeBitSize(primType), regType);
2325         DEBUG_ASSERT(addrOpnd->IsMemoryAccessOperand(), "NIY, must be mem opnd");
2326         auto *newMemOpnd =
2327             &GetMemOperandAddOffset(static_cast<MemOperand &>(*addrOpnd), offset, GetPrimTypeBitSize(primType));
2328         MOperator ldMop = PickLdInsn(GetPrimTypeBitSize(primType), primType);
2329         Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, phyReg, *newMemOpnd);
2330         ldInsn.MarkAsAccessRefField(isRefField);
2331         GetCurBB()->AppendInsn(ldInsn);
2332         if (!VERIFY_INSN(&ldInsn)) {
2333             SPLIT_INSN(&ldInsn, this);
2334         }
2335 
2336         offset += GetPrimTypeSize(primType);
2337         result.push_back(&phyReg);
2338     };
2339     generateReturnValToRegs(retMatch.GetReg0(), retMatch.GetPrimTypeOfReg0());
2340     if (retMatch.GetReg1() != kRinvalid) {
2341         generateReturnValToRegs(retMatch.GetReg1(), retMatch.GetPrimTypeOfReg1());
2342     }
2343     if (retMatch.GetReg2() != kRinvalid) {
2344         generateReturnValToRegs(retMatch.GetReg2(), retMatch.GetPrimTypeOfReg2());
2345     }
2346     if (retMatch.GetReg3() != kRinvalid) {
2347         generateReturnValToRegs(retMatch.GetReg3(), retMatch.GetPrimTypeOfReg3());
2348     }
2349 }
2350 
SelectDread(const BaseNode & parent,DreadNode & expr)2351 Operand *AArch64CGFunc::SelectDread(const BaseNode &parent, DreadNode &expr)
2352 {
2353     MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(expr.GetStIdx());
2354     auto itr = stIdx2OverflowResult.find(expr.GetStIdx());
2355     if (itr != stIdx2OverflowResult.end()) {
2356         /* add_with_overflow / sub_with_overflow:
2357          * reg1: param1
2358          * reg2: param2
2359          * adds/subs reg3, reg1, reg2
2360          * cset reg4, vs
2361          * result is saved in std::pair<RegOperand*, RegOperand*>(reg3, reg4)
2362          */
2363         if (expr.GetFieldID() == 1) {
2364             return itr->second.first;
2365         } else {
2366             DEBUG_ASSERT(expr.GetFieldID() == 2, "only has 2 fields for intrinsic overflow call result"); // 2 fields
2367             return itr->second.second;
2368         }
2369     }
2370     if (symbol->IsEhIndex()) {
2371         CHECK_FATAL(false, "should not go here");
2372         MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast<TyIdx>(PTY_i32));
2373         /* use the second register return by __builtin_eh_return(). */
2374         AArch64CallConvImpl retLocator(GetBecommon());
2375         CCLocInfo retMech;
2376         retLocator.LocateRetVal(*type, retMech);
2377         retLocator.SetupSecondRetReg(*type, retMech);
2378         return &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(retMech.GetReg1()), k64BitSize, kRegTyInt);
2379     }
2380 
2381     PrimType symType = symbol->GetType()->GetPrimType();
2382     uint32 offset = 0;
2383     bool parmCopy = false;
2384     if (expr.GetFieldID() != 0) {
2385         MIRStructType *structType = static_cast<MIRStructType *>(symbol->GetType());
2386         DEBUG_ASSERT(structType != nullptr, "SelectDread: non-zero fieldID for non-structure");
2387         symType = structType->GetFieldType(expr.GetFieldID())->GetPrimType();
2388         offset = static_cast<uint32>(GetBecommon().GetFieldOffset(*structType, expr.GetFieldID()).first);
2389         parmCopy = IsParamStructCopy(*symbol);
2390     }
2391 
2392     uint32 dataSize = GetPrimTypeBitSize(symType);
2393     uint32 aggSize = 0;
2394     PrimType resultType = expr.GetPrimType();
2395     if (symType == PTY_agg) {
2396         if (expr.GetPrimType() == PTY_agg) {
2397             aggSize = static_cast<uint32>(GetBecommon().GetTypeSize(symbol->GetType()->GetTypeIndex().GetIdx()));
2398             dataSize = ((expr.GetFieldID() == 0) ? GetPointerSize() : aggSize) << k8BitShift;
2399             resultType = PTY_u64;
2400             symType = resultType;
2401         } else {
2402             dataSize = GetPrimTypeBitSize(expr.GetPrimType());
2403         }
2404     }
2405     MemOperand *memOpnd = nullptr;
2406     if (aggSize > k8ByteSize) {
2407         if (parent.op == OP_eval) {
2408             if (symbol->GetAttr(ATTR_volatile)) {
2409                 /* Need to generate loads for the upper parts of the struct. */
2410                 Operand &dest = GetZeroOpnd(k64BitSize);
2411                 uint32 numLoads = static_cast<uint32>(RoundUp(aggSize, k64BitSize) / k64BitSize);
2412                 for (uint32 o = 0; o < numLoads; ++o) {
2413                     if (parmCopy) {
2414                         memOpnd = &LoadStructCopyBase(*symbol, offset + o * GetPointerSize(), GetPointerSize());
2415                     } else {
2416                         memOpnd = &GetOrCreateMemOpnd(*symbol, offset + o * GetPointerSize(), GetPointerSize());
2417                     }
2418                     if (IsImmediateOffsetOutOfRange(*memOpnd, GetPointerSize())) {
2419                         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, GetPointerSize());
2420                     }
2421                     SelectCopy(dest, PTY_u64, *memOpnd, PTY_u64);
2422                 }
2423             } else {
2424                 /* No side-effects.  No need to generate anything for eval. */
2425             }
2426         } else {
2427             if (expr.GetFieldID() != 0) {
2428                 CHECK_FATAL(false, "SelectDread: Illegal agg size");
2429             }
2430         }
2431     }
2432     if (parmCopy) {
2433         memOpnd = &LoadStructCopyBase(*symbol, offset, static_cast<int>(dataSize));
2434     } else {
2435         memOpnd = &GetOrCreateMemOpnd(*symbol, offset, dataSize);
2436     }
2437     if ((memOpnd->GetMemVaryType() == kNotVary) && IsImmediateOffsetOutOfRange(*memOpnd, dataSize)) {
2438         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, dataSize);
2439     }
2440 
2441     RegOperand &resOpnd = GetOrCreateResOperand(parent, symType);
2442     /* a local register variable defined with a specified register */
2443     if (symbol->GetAsmAttr() != UStrIdx(0) && symbol->GetStorageClass() != kScPstatic &&
2444         symbol->GetStorageClass() != kScFstatic) {
2445         std::string regDesp = GlobalTables::GetUStrTable().GetStringFromStrIdx(symbol->GetAsmAttr());
2446         RegOperand &specifiedOpnd = GetOrCreatePhysicalRegisterOperand(regDesp);
2447         return &specifiedOpnd;
2448     }
2449     memOpnd =
2450         memOpnd->IsOffsetMisaligned(dataSize) ? &ConstraintOffsetToSafeRegion(dataSize, *memOpnd, symbol) : memOpnd;
2451     SelectCopy(resOpnd, resultType, *memOpnd, symType);
2452     return &resOpnd;
2453 }
2454 
SelectRegread(RegreadNode & expr)2455 RegOperand *AArch64CGFunc::SelectRegread(RegreadNode &expr)
2456 {
2457     PregIdx pregIdx = expr.GetRegIdx();
2458     if (IsSpecialPseudoRegister(pregIdx)) {
2459         /* if it is one of special registers */
2460         return &GetOrCreateSpecialRegisterOperand(-pregIdx, expr.GetPrimType());
2461     }
2462     RegOperand &reg = GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
2463     if (GetOpndFromPregIdx(pregIdx) == nullptr) {
2464         SetPregIdx2Opnd(pregIdx, reg);
2465     }
2466     if (expr.GetPrimType() == PTY_ref) {
2467         reg.SetIsReference(true);
2468         AddReferenceReg(reg.GetRegisterNumber());
2469     }
2470     if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
2471         MemOperand *src = GetPseudoRegisterSpillMemoryOperand(pregIdx);
2472         MIRPreg *preg = GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
2473         PrimType stype = preg->GetPrimType();
2474         uint32 srcBitLength = GetPrimTypeSize(stype) * kBitsPerByte;
2475         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(srcBitLength, stype), reg, *src));
2476     }
2477     return &reg;
2478 }
2479 
SelectAddrof(Operand & result,StImmOperand & stImm,FieldID field)2480 void AArch64CGFunc::SelectAddrof(Operand &result, StImmOperand &stImm, FieldID field)
2481 {
2482     const MIRSymbol *symbol = stImm.GetSymbol();
2483     if (symbol->GetStorageClass() == kScAuto) {
2484         SetStackProtectInfo(kAddrofStack);
2485     }
2486     if ((symbol->GetStorageClass() == kScAuto) || (symbol->GetStorageClass() == kScFormal)) {
2487         if (!CGOptions::IsQuiet()) {
2488             maple::LogInfo::MapleLogger(kLlErr)
2489                 << "Warning: we expect AddrOf with StImmOperand is not used for local variables";
2490         }
2491         AArch64SymbolAlloc *symLoc =
2492             static_cast<AArch64SymbolAlloc *>(GetMemlayout()->GetSymAllocInfo(symbol->GetStIndex()));
2493         ImmOperand *offset = nullptr;
2494         if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) {
2495             offset = &CreateImmOperand(GetBaseOffset(*symLoc) + stImm.GetOffset(), k64BitSize, false, kUnAdjustVary);
2496         } else if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsRefLocals) {
2497             auto it = immOpndsRequiringOffsetAdjustmentForRefloc.find(symLoc);
2498             if (it != immOpndsRequiringOffsetAdjustmentForRefloc.end()) {
2499                 offset = (*it).second;
2500             } else {
2501                 offset = &CreateImmOperand(GetBaseOffset(*symLoc) + stImm.GetOffset(), k64BitSize, false);
2502                 immOpndsRequiringOffsetAdjustmentForRefloc[symLoc] = offset;
2503             }
2504         } else {
2505             /* Do not cache modified symbol location */
2506             offset = &CreateImmOperand(GetBaseOffset(*symLoc) + stImm.GetOffset(), k64BitSize, false);
2507         }
2508 
2509         SelectAdd(result, *GetBaseReg(*symLoc), *offset, PTY_u64);
2510         if (GetCG()->GenerateVerboseCG()) {
2511             /* Add a comment */
2512             Insn *insn = GetCurBB()->GetLastInsn();
2513             std::string comm = "local/formal var: ";
2514             comm += symbol->GetName();
2515             insn->SetComment(comm);
2516         }
2517     } else if (symbol->IsThreadLocal()) {
2518         SelectAddrofThreadLocal(result, stImm);
2519         return;
2520     } else {
2521         Operand *srcOpnd = &result;
2522         if (!IsAfterRegAlloc()) {
2523             // Create a new vreg/preg for the upper bits of the address
2524             PregIdx pregIdx = GetFunction().GetPregTab()->CreatePreg(PTY_a64);
2525             MIRPreg *tmpPreg = GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
2526             regno_t vRegNO = NewVReg(kRegTyInt, GetPrimTypeSize(PTY_a64));
2527             RegOperand &tmpreg = GetOrCreateVirtualRegisterOperand(vRegNO);
2528 
2529             // Register this vreg mapping
2530             RegisterVregMapping(vRegNO, pregIdx);
2531 
2532             // Store rematerialization info in the preg
2533             tmpPreg->SetOp(OP_addrof);
2534             tmpPreg->rematInfo.sym = symbol;
2535             tmpPreg->fieldID = field;
2536             tmpPreg->addrUpper = true;
2537 
2538             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, tmpreg, stImm));
2539             srcOpnd = &tmpreg;
2540         } else {
2541             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, result, stImm));
2542         }
2543         if (CGOptions::IsPIC() && symbol->NeedPIC()) {
2544             OfstOperand &offset = CreateOfstOpnd(*stImm.GetSymbol(), stImm.GetOffset(), stImm.GetRelocs());
2545 
2546             auto size = GetPointerSize() * kBitsPerByte;
2547             MemOperand &memOpnd = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, size, static_cast<RegOperand *>(srcOpnd),
2548                                                      nullptr, &offset, nullptr);
2549             GetCurBB()->AppendInsn(
2550                 GetInsnBuilder()->BuildInsn(size == k64BitSize ? MOP_xldr : MOP_wldr, result, memOpnd));
2551 
2552             if (stImm.GetOffset() > 0) {
2553                 ImmOperand &immOpnd = CreateImmOperand(stImm.GetOffset(), result.GetSize(), false);
2554                 SelectAdd(result, result, immOpnd, PTY_u64);
2555             }
2556         } else {
2557             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, result, *srcOpnd, stImm));
2558         }
2559     }
2560 }
2561 
SelectAddrof(Operand & result,MemOperand & memOpnd,FieldID field)2562 void AArch64CGFunc::SelectAddrof(Operand &result, MemOperand &memOpnd, FieldID field)
2563 {
2564     const MIRSymbol *symbol = memOpnd.GetSymbol();
2565     if (symbol->GetStorageClass() == kScAuto) {
2566         auto *offsetOpnd = static_cast<OfstOperand *>(memOpnd.GetOffsetImmediate());
2567         Operand &immOpnd = CreateImmOperand(offsetOpnd->GetOffsetValue(), PTY_u32, false);
2568         DEBUG_ASSERT(memOpnd.GetBaseRegister() != nullptr, "nullptr check");
2569         SelectAdd(result, *memOpnd.GetBaseRegister(), immOpnd, PTY_u32);
2570         SetStackProtectInfo(kAddrofStack);
2571     } else if (!IsAfterRegAlloc()) {
2572         // Create a new vreg/preg for the upper bits of the address
2573         PregIdx pregIdx = GetFunction().GetPregTab()->CreatePreg(PTY_a64);
2574         MIRPreg *tmpPreg = GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
2575         regno_t vRegNO = NewVReg(kRegTyInt, GetPrimTypeSize(PTY_a64));
2576         RegOperand &tmpreg = GetOrCreateVirtualRegisterOperand(vRegNO);
2577 
2578         // Register this vreg mapping
2579         RegisterVregMapping(vRegNO, pregIdx);
2580 
2581         // Store rematerialization info in the preg
2582         tmpPreg->SetOp(OP_addrof);
2583         tmpPreg->rematInfo.sym = symbol;
2584         tmpPreg->fieldID = field;
2585         tmpPreg->addrUpper = true;
2586 
2587         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, tmpreg, memOpnd));
2588         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, result, tmpreg, memOpnd));
2589     } else {
2590         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, result, memOpnd));
2591         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, result, result, memOpnd));
2592     }
2593 }
2594 
SelectAddrof(AddrofNode & expr,const BaseNode & parent,bool isAddrofoff)2595 Operand *AArch64CGFunc::SelectAddrof(AddrofNode &expr, const BaseNode &parent, bool isAddrofoff)
2596 {
2597     MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(expr.GetStIdx());
2598     DEBUG_ASSERT(symbol != nullptr, "symbol should not be nullptr");
2599     int32 offset = 0;
2600     AddrofoffNode &addrofoffExpr = static_cast<AddrofoffNode &>(static_cast<BaseNode &>(expr));
2601     if (isAddrofoff) {
2602         offset = addrofoffExpr.offset;
2603     } else {
2604         if (expr.GetFieldID() != 0) {
2605             MIRStructType *structType = static_cast<MIRStructType *>(symbol->GetType());
2606             /* with array of structs, it is possible to have nullptr */
2607             if (structType != nullptr) {
2608                 offset = GetBecommon().GetFieldOffset(*structType, expr.GetFieldID()).first;
2609             }
2610         }
2611     }
2612     if ((symbol->GetStorageClass() == kScFormal) && (symbol->GetSKind() == kStVar) &&
2613         ((!isAddrofoff && expr.GetFieldID() != 0) ||
2614          (GetBecommon().GetTypeSize(symbol->GetType()->GetTypeIndex().GetIdx()) > k16ByteSize))) {
2615         /*
2616          * Struct param is copied on the stack by caller if struct size > 16.
2617          * Else if size < 16 then struct param is copied into one or two registers.
2618          */
2619         RegOperand *stackAddr = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
2620         /* load the base address of the struct copy from stack. */
2621         SelectAddrof(*stackAddr, CreateStImmOperand(*symbol, 0, 0));
2622         Operand *structAddr;
2623         if (!IsParamStructCopy(*symbol)) {
2624             isAggParamInReg = true;
2625             structAddr = stackAddr;
2626         } else {
2627             OfstOperand *offopnd = &CreateOfstOpnd(0, k32BitSize);
2628             MemOperand *mo = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, GetPointerSize() * kBitsPerByte, stackAddr,
2629                                                  nullptr, offopnd, nullptr);
2630             structAddr = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
2631             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xldr, *structAddr, *mo));
2632         }
2633         if (offset == 0) {
2634             return structAddr;
2635         } else {
2636             /* add the struct offset to the base address */
2637             Operand *result = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
2638             ImmOperand *imm = &CreateImmOperand(PTY_a64, offset);
2639             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *result, *structAddr, *imm));
2640             return result;
2641         }
2642     }
2643     PrimType ptype = expr.GetPrimType();
2644     Operand &result = GetOrCreateResOperand(parent, ptype);
2645     if (symbol->IsReflectionClassInfo() && !symbol->IsReflectionArrayClassInfo() && !GetCG()->IsLibcore()) {
2646         std::string ptrName = namemangler::kPtrPrefixStr + symbol->GetName();
2647         MIRType *ptrType = GlobalTables::GetTypeTable().GetPtr();
2648         symbol = GetMirModule().GetMIRBuilder()->GetOrCreateGlobalDecl(ptrName, *ptrType);
2649         symbol->SetStorageClass(kScFstatic);
2650 
2651         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_adrp_ldr, result, CreateStImmOperand(*symbol, 0, 0)));
2652         /* make it un rematerializable. */
2653         MIRPreg *preg = GetPseudoRegFromVirtualRegNO(static_cast<RegOperand &>(result).GetRegisterNumber());
2654         if (preg) {
2655             preg->SetOp(OP_undef);
2656         }
2657         return &result;
2658     }
2659 
2660     SelectAddrof(result, CreateStImmOperand(*symbol, offset, 0), isAddrofoff ? 0 : expr.GetFieldID());
2661     return &result;
2662 }
2663 
SelectAddrofoff(AddrofoffNode & expr,const BaseNode & parent)2664 Operand *AArch64CGFunc::SelectAddrofoff(AddrofoffNode &expr, const BaseNode &parent)
2665 {
2666     return SelectAddrof(static_cast<AddrofNode &>(static_cast<BaseNode &>(expr)), parent, true);
2667 }
2668 
SelectAddrofFunc(AddroffuncNode & expr,const BaseNode & parent)2669 Operand &AArch64CGFunc::SelectAddrofFunc(AddroffuncNode &expr, const BaseNode &parent)
2670 {
2671     uint32 instrSize = static_cast<uint32>(expr.SizeOfInstr());
2672     PrimType primType = (instrSize == k8ByteSize)
2673                             ? PTY_u64
2674                             : (instrSize == k4ByteSize) ? PTY_u32 : (instrSize == k2ByteSize) ? PTY_u16 : PTY_u8;
2675     Operand &operand = GetOrCreateResOperand(parent, primType);
2676     MIRFunction *mirFunction = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(expr.GetPUIdx());
2677     CHECK_NULL_FATAL(mirFunction->GetFuncSymbol());
2678     SelectAddrof(operand, CreateStImmOperand(*mirFunction->GetFuncSymbol(), 0, 0));
2679     return operand;
2680 }
2681 
2682 /* For an entire aggregate that can fit inside a single 8 byte register.  */
GetDestTypeFromAggSize(uint32 bitSize) const2683 PrimType AArch64CGFunc::GetDestTypeFromAggSize(uint32 bitSize) const
2684 {
2685     PrimType primType;
2686     switch (bitSize) {
2687         case k8BitSize: {
2688             primType = PTY_u8;
2689             break;
2690         }
2691         case k16BitSize: {
2692             primType = PTY_u16;
2693             break;
2694         }
2695         case k32BitSize: {
2696             primType = PTY_u32;
2697             break;
2698         }
2699         case k64BitSize: {
2700             primType = PTY_u64;
2701             break;
2702         }
2703         default:
2704             CHECK_FATAL(false, "aggregate of unhandled size");
2705     }
2706     return primType;
2707 }
2708 
SelectAddrofLabel(AddroflabelNode & expr,const BaseNode & parent)2709 Operand &AArch64CGFunc::SelectAddrofLabel(AddroflabelNode &expr, const BaseNode &parent)
2710 {
2711     /* adrp reg, label-id */
2712     uint32 instrSize = static_cast<uint32>(expr.SizeOfInstr());
2713     PrimType primType = (instrSize == k8ByteSize)
2714                             ? PTY_u64
2715                             : (instrSize == k4ByteSize) ? PTY_u32 : (instrSize == k2ByteSize) ? PTY_u16 : PTY_u8;
2716     Operand &dst = GetOrCreateResOperand(parent, primType);
2717     Operand &immOpnd = CreateImmOperand(expr.GetOffset(), k64BitSize, false);
2718     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_adrp_label, dst, immOpnd));
2719     return dst;
2720 }
2721 
SelectIreadoff(const BaseNode & parent,IreadoffNode & ireadoff)2722 Operand *AArch64CGFunc::SelectIreadoff(const BaseNode &parent, IreadoffNode &ireadoff)
2723 {
2724     auto offset = ireadoff.GetOffset();
2725     auto primType = ireadoff.GetPrimType();
2726     auto bitSize = GetPrimTypeBitSize(primType);
2727     auto *baseAddr = ireadoff.Opnd(0);
2728     auto *result = &CreateRegisterOperandOfType(primType);
2729     auto *addrOpnd = HandleExpr(ireadoff, *baseAddr);
2730     ASSERT_NOT_NULL(addrOpnd);
2731     if (primType == PTY_agg && parent.GetOpCode() == OP_regassign) {
2732         auto &memOpnd = CreateMemOpnd(LoadIntoRegister(*addrOpnd, PTY_a64), offset, bitSize);
2733         auto mop = PickLdInsn(64, PTY_a64);
2734         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, *result, memOpnd));
2735         auto &regAssignNode = static_cast<const RegassignNode &>(parent);
2736         PregIdx pIdx = regAssignNode.GetRegIdx();
2737         CHECK_FATAL(IsSpecialPseudoRegister(pIdx), "SelectIreadfpoff of agg");
2738         (void)LmbcSmallAggForRet(parent, addrOpnd, offset, true);
2739         // result not used
2740     } else {
2741         auto &memOpnd = CreateMemOpnd(LoadIntoRegister(*addrOpnd, PTY_a64), offset, bitSize);
2742         auto mop = PickLdInsn(bitSize, primType);
2743         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, *result, memOpnd));
2744     }
2745     return result;
2746 }
2747 
GenLmbcParamLoad(int32 offset,uint32 byteSize,RegType regType,PrimType primType,AArch64reg baseRegno)2748 RegOperand *AArch64CGFunc::GenLmbcParamLoad(int32 offset, uint32 byteSize, RegType regType, PrimType primType,
2749                                             AArch64reg baseRegno)
2750 {
2751     MemOperand *memOpnd = GenLmbcFpMemOperand(offset, byteSize, baseRegno);
2752     RegOperand *result = &GetOrCreateVirtualRegisterOperand(NewVReg(regType, byteSize));
2753     MOperator mOp = PickLdInsn(byteSize * kBitsPerByte, primType);
2754     Insn &load = GetInsnBuilder()->BuildInsn(mOp, *result, *memOpnd);
2755     GetCurBB()->AppendInsn(load);
2756     return result;
2757 }
2758 
LmbcStructReturnLoad(int32 offset)2759 RegOperand *AArch64CGFunc::LmbcStructReturnLoad(int32 offset)
2760 {
2761     RegOperand *result = nullptr;
2762     MIRFunction &func = GetFunction();
2763     CHECK_FATAL(func.IsReturnStruct(), "LmbcStructReturnLoad: not struct return");
2764     MIRType *ty = func.GetReturnType();
2765     uint32 sz = GetBecommon().GetTypeSize(ty->GetTypeIndex());
2766     uint32 fpSize;
2767     uint32 numFpRegs = FloatParamRegRequired(static_cast<MIRStructType *>(ty), fpSize);
2768     if (numFpRegs > 0) {
2769         PrimType pType = (fpSize <= k4ByteSize) ? PTY_f32 : PTY_f64;
2770         for (int32 i = (numFpRegs - kOneRegister); i > 0; --i) {
2771             result = GenLmbcParamLoad(offset + (i * static_cast<int32>(fpSize)), fpSize, kRegTyFloat, pType);
2772             AArch64reg regNo = static_cast<AArch64reg>(V0 + static_cast<uint32>(i));
2773             RegOperand *reg = &GetOrCreatePhysicalRegisterOperand(regNo, fpSize * kBitsPerByte, kRegTyFloat);
2774             SelectCopy(*reg, pType, *result, pType);
2775             Insn &pseudo = GetInsnBuilder()->BuildInsn(MOP_pseudo_ret_float, *reg);
2776             GetCurBB()->AppendInsn(pseudo);
2777         }
2778         result = GenLmbcParamLoad(offset, fpSize, kRegTyFloat, pType);
2779     } else if (sz <= k4ByteSize) {
2780         result = GenLmbcParamLoad(offset, k4ByteSize, kRegTyInt, PTY_u32);
2781     } else if (sz <= k8ByteSize) {
2782         result = GenLmbcParamLoad(offset, k8ByteSize, kRegTyInt, PTY_i64);
2783     } else if (sz <= k16ByteSize) {
2784         result = GenLmbcParamLoad(offset + k8ByteSizeInt, k8ByteSize, kRegTyInt, PTY_i64);
2785         RegOperand *r1 = &GetOrCreatePhysicalRegisterOperand(R1, k8ByteSize * kBitsPerByte, kRegTyInt);
2786         SelectCopy(*r1, PTY_i64, *result, PTY_i64);
2787         Insn &pseudo = GetInsnBuilder()->BuildInsn(MOP_pseudo_ret_int, *r1);
2788         GetCurBB()->AppendInsn(pseudo);
2789         result = GenLmbcParamLoad(offset, k8ByteSize, kRegTyInt, PTY_i64);
2790     }
2791     return result;
2792 }
2793 
SelectIreadfpoff(const BaseNode & parent,IreadFPoffNode & ireadoff)2794 Operand *AArch64CGFunc::SelectIreadfpoff(const BaseNode &parent, IreadFPoffNode &ireadoff)
2795 {
2796     uint32 offset = static_cast<uint32>(ireadoff.GetOffset());
2797     PrimType primType = ireadoff.GetPrimType();
2798     uint32 bytelen = GetPrimTypeSize(primType);
2799     uint32 bitlen = bytelen * kBitsPerByte;
2800     RegType regty = GetRegTyFromPrimTy(primType);
2801     RegOperand *result = nullptr;
2802     if (offset >= 0) {
2803         LmbcFormalParamInfo *info = GetLmbcFormalParamInfo(static_cast<uint32>(offset));
2804         DEBUG_ASSERT(info != nullptr, "nullptr check");
2805         if (info->GetPrimType() == PTY_agg) {
2806             if (info->IsOnStack()) {
2807                 result = GenLmbcParamLoad(info->GetOnStackOffset(), GetPrimTypeSize(PTY_a64), kRegTyInt, PTY_a64);
2808                 regno_t baseRegno = result->GetRegisterNumber();
2809                 result = GenLmbcParamLoad(offset - static_cast<int32>(info->GetOffset()), bytelen, regty, primType,
2810                                           (AArch64reg)baseRegno);
2811             } else if (primType == PTY_agg) {
2812                 CHECK_FATAL(parent.GetOpCode() == OP_regassign, "SelectIreadfpoff of agg");
2813                 result = LmbcStructReturnLoad(offset);
2814             } else {
2815                 result = GenLmbcParamLoad(offset, bytelen, regty, primType);
2816             }
2817         } else {
2818             CHECK_FATAL(primType == info->GetPrimType(), "Incorrect primtype");
2819             CHECK_FATAL(offset == info->GetOffset(), "Incorrect offset");
2820             if (info->GetRegNO() == 0 || !info->HasRegassign()) {
2821                 result = GenLmbcParamLoad(offset, bytelen, regty, primType);
2822             } else {
2823                 result = &GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(info->GetRegNO()), bitlen, regty);
2824             }
2825         }
2826     } else {
2827         if (primType == PTY_agg) {
2828             CHECK_FATAL(parent.GetOpCode() == OP_regassign, "SelectIreadfpoff of agg");
2829             result = LmbcStructReturnLoad(offset);
2830         } else {
2831             result = GenLmbcParamLoad(offset, bytelen, regty, primType);
2832         }
2833     }
2834     return result;
2835 }
2836 
SelectIread(const BaseNode & parent,IreadNode & expr,int extraOffset,PrimType finalBitFieldDestType)2837 Operand *AArch64CGFunc::SelectIread(const BaseNode &parent, IreadNode &expr, int extraOffset,
2838                                     PrimType finalBitFieldDestType)
2839 {
2840     int32 offset = 0;
2841     MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(expr.GetTyIdx());
2842     MIRPtrType *pointerType = static_cast<MIRPtrType *>(type);
2843     DEBUG_ASSERT(pointerType != nullptr, "expect a pointer type at iread node");
2844     MIRType *pointedType = nullptr;
2845     bool isRefField = false;
2846     AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone;
2847 
2848     if (expr.GetFieldID() != 0) {
2849         MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx());
2850         MIRStructType *structType = nullptr;
2851         if (pointedTy->GetKind() != kTypeJArray) {
2852             structType = static_cast<MIRStructType *>(pointedTy);
2853         } else {
2854             structType = static_cast<MIRJarrayType *>(pointedTy)->GetParentType();
2855         }
2856 
2857         DEBUG_ASSERT(structType != nullptr, "SelectIread: non-zero fieldID for non-structure");
2858         pointedType = structType->GetFieldType(expr.GetFieldID());
2859         offset = GetBecommon().GetFieldOffset(*structType, expr.GetFieldID()).first;
2860         isRefField = GetBecommon().IsRefField(*structType, expr.GetFieldID());
2861     } else {
2862         pointedType = GetPointedToType(*pointerType);
2863     }
2864 
2865     RegType regType = GetRegTyFromPrimTy(expr.GetPrimType());
2866     uint32 regSize = GetPrimTypeSize(expr.GetPrimType());
2867     if (expr.GetFieldID() == 0 && pointedType->GetPrimType() == PTY_agg) {
2868         /* Maple IR can passing small struct to be loaded into a single register. */
2869         if (regType == kRegTyFloat) {
2870             /* regsize is correct */
2871         } else {
2872             uint32 sz = GetBecommon().GetTypeSize(pointedType->GetTypeIndex().GetIdx());
2873             regSize = (sz <= k4ByteSize) ? k4ByteSize : k8ByteSize;
2874         }
2875     } else if (regSize < k4ByteSize) {
2876         regSize = k4ByteSize; /* 32-bit */
2877     }
2878     Operand *result = nullptr;
2879     constexpr int regSizeMax = 8;
2880     if (parent.GetOpCode() == OP_eval && regSize <= regSizeMax) {
2881         /* regSize << 3, that is regSize * 8, change bytes to bits */
2882         result = &GetZeroOpnd(regSize << 3);
2883     } else {
2884         result = &GetOrCreateResOperand(parent, expr.GetPrimType());
2885     }
2886 
2887     PrimType destType = pointedType->GetPrimType();
2888 
2889     uint32 bitSize = 0;
2890     if ((pointedType->GetKind() == kTypeStructIncomplete) || (pointedType->GetKind() == kTypeClassIncomplete) ||
2891         (pointedType->GetKind() == kTypeInterfaceIncomplete)) {
2892         bitSize = GetPrimTypeBitSize(expr.GetPrimType());
2893         maple::LogInfo::MapleLogger(kLlErr) << "Warning: objsize is zero! \n";
2894     } else {
2895         if (pointedType->IsStructType()) {
2896             MIRStructType *structType = static_cast<MIRStructType *>(pointedType);
2897             /* size << 3, that is size * 8, change bytes to bits */
2898             bitSize = std::min(structType->GetSize(), static_cast<size_t>(GetPointerSize())) << 3;
2899         } else {
2900             bitSize = GetPrimTypeBitSize(destType);
2901         }
2902         if (regType == kRegTyFloat) {
2903             destType = expr.GetPrimType();
2904             bitSize = GetPrimTypeBitSize(destType);
2905         } else if (destType == PTY_agg) {
2906             switch (bitSize) {
2907                 case k8BitSize:
2908                     destType = PTY_u8;
2909                     break;
2910                 case k16BitSize:
2911                     destType = PTY_u16;
2912                     break;
2913                 case k32BitSize:
2914                     destType = PTY_u32;
2915                     break;
2916                 case k64BitSize:
2917                     destType = PTY_u64;
2918                     break;
2919                 default:
2920                     destType = PTY_u64;  // when eval agg . a way to round up
2921                     DEBUG_ASSERT(bitSize == 0, " round up empty agg ");
2922                     bitSize = k64BitSize;
2923                     break;
2924             }
2925         }
2926     }
2927 
2928     PrimType memType = (finalBitFieldDestType == kPtyInvalid ? destType : finalBitFieldDestType);
2929     MemOperand *memOpnd = CreateMemOpndOrNull(memType, expr, *expr.Opnd(0),
2930                                               static_cast<int64>(static_cast<int>(offset) + extraOffset), memOrd);
2931     if (aggParamReg != nullptr) {
2932         isAggParamInReg = false;
2933         return aggParamReg;
2934     }
2935     DEBUG_ASSERT(memOpnd != nullptr, "memOpnd should not be nullptr");
2936     if (isVolLoad && (memOpnd->GetAddrMode() == MemOperand::kAddrModeBOi)) {
2937         memOrd = AArch64isa::kMoAcquire;
2938         isVolLoad = false;
2939     }
2940 
2941     memOpnd =
2942         memOpnd->IsOffsetMisaligned(bitSize) ? &ConstraintOffsetToSafeRegion(bitSize, *memOpnd, nullptr) : memOpnd;
2943     if (memOrd == AArch64isa::kMoNone) {
2944         MOperator mOp = 0;
2945         if (finalBitFieldDestType == kPtyInvalid) {
2946             mOp = PickLdInsn(bitSize, destType);
2947         } else {
2948             mOp = PickLdInsn(GetPrimTypeBitSize(finalBitFieldDestType), finalBitFieldDestType);
2949         }
2950         if ((memOpnd->GetMemVaryType() == kNotVary) && !IsOperandImmValid(mOp, memOpnd, 1)) {
2951             memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, bitSize);
2952         }
2953         Insn &insn = GetInsnBuilder()->BuildInsn(mOp, *result, *memOpnd);
2954         if (parent.GetOpCode() == OP_eval && result->IsRegister() &&
2955             static_cast<RegOperand *>(result)->GetRegisterNumber() == RZR) {
2956             insn.SetComment("null-check");
2957         }
2958         GetCurBB()->AppendInsn(insn);
2959 
2960         if (parent.op != OP_eval) {
2961             const InsnDesc *md = &AArch64CG::kMd[insn.GetMachineOpcode()];
2962             auto *prop = md->GetOpndDes(0);
2963             if ((prop->GetSize()) < insn.GetOperand(0).GetSize()) {
2964                 switch (destType) {
2965                     case PTY_i8:
2966                         mOp = MOP_xsxtb64;
2967                         break;
2968                     case PTY_i16:
2969                         mOp = MOP_xsxth64;
2970                         break;
2971                     case PTY_i32:
2972                         mOp = MOP_xsxtw64;
2973                         break;
2974                     case PTY_u1:
2975                     case PTY_u8:
2976                         mOp = MOP_xuxtb32;
2977                         break;
2978                     case PTY_u16:
2979                         mOp = MOP_xuxth32;
2980                         break;
2981                     case PTY_u32:
2982                         mOp = MOP_xuxtw64;
2983                         break;
2984                     default:
2985                         break;
2986                 }
2987                 if (destType == PTY_u1) {
2988                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wandrri12, insn.GetOperand(0),
2989                                                                        insn.GetOperand(0),
2990                                                                        CreateImmOperand(1, kMaxImmVal5Bits, false)));
2991                 }
2992 
2993                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, insn.GetOperand(0), insn.GetOperand(0)));
2994             }
2995         }
2996     } else {
2997         if ((memOpnd->GetMemVaryType() == kNotVary) && IsImmediateOffsetOutOfRange(*memOpnd, bitSize)) {
2998             memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, bitSize);
2999         }
3000         AArch64CGFunc::SelectLoadAcquire(*result, destType, *memOpnd, destType, memOrd, false);
3001     }
3002     if (GetCurBB() && GetCurBB()->GetLastMachineInsn()) {
3003         GetCurBB()->GetLastMachineInsn()->MarkAsAccessRefField(isRefField);
3004     }
3005     return result;
3006 }
3007 
SelectIntConst(const MIRIntConst & intConst,const BaseNode & parent)3008 Operand *AArch64CGFunc::SelectIntConst(const MIRIntConst &intConst, const BaseNode &parent)
3009 {
3010     auto primType = intConst.GetType().GetPrimType();
3011     if (kOpcodeInfo.IsCompare(parent.GetOpCode())) {
3012         primType = static_cast<const CompareNode &>(parent).GetOpndType();
3013     }
3014     return &CreateImmOperand(intConst.GetExtValue(), GetPrimTypeBitSize(primType), false);
3015 }
3016 
SelectIntConst(const MIRIntConst & intConst)3017 Operand *AArch64CGFunc::SelectIntConst(const MIRIntConst &intConst)
3018 {
3019     return &CreateImmOperand(intConst.GetExtValue(), GetPrimTypeSize(intConst.GetType().GetPrimType()) * kBitsPerByte,
3020                              false);
3021 }
3022 
HandleFmovImm(PrimType stype,int64 val,MIRConst & mirConst,const BaseNode & parent)3023 Operand *AArch64CGFunc::HandleFmovImm(PrimType stype, int64 val, MIRConst &mirConst, const BaseNode &parent)
3024 {
3025     Operand *result;
3026     bool is64Bits = (GetPrimTypeBitSize(stype) == k64BitSize);
3027     uint64 canRepreset = is64Bits ? (val & 0xffffffffffff) : (val & 0x7ffff);
3028     uint32 val1 = is64Bits ? (val >> 61) & 0x3 : (val >> 29) & 0x3;
3029     uint32 val2 = is64Bits ? (val >> 54) & 0xff : (val >> 25) & 0x1f;
3030     bool isSame = is64Bits ? ((val2 == 0) || (val2 == 0xff)) : ((val2 == 0) || (val2 == 0x1f));
3031     canRepreset = (canRepreset == 0) && ((val1 & 0x1) ^ ((val1 & 0x2) >> 1)) && isSame;
3032     if (canRepreset) {
3033         uint64 temp1 = is64Bits ? (val >> 63) << 7 : (val >> 31) << 7;
3034         uint64 temp2 = is64Bits ? val >> 48 : val >> 19;
3035         int64 imm8 = (temp2 & 0x7f) | temp1;
3036         Operand *newOpnd0 = &CreateImmOperand(imm8, k8BitSize, true, kNotVary, true);
3037         result = &GetOrCreateResOperand(parent, stype);
3038         MOperator mopFmov = (is64Bits ? MOP_xdfmovri : MOP_wsfmovri);
3039         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopFmov, *result, *newOpnd0));
3040     } else {
3041         Operand *newOpnd0 = &CreateImmOperand(val, GetPrimTypeSize(stype) * kBitsPerByte, false);
3042         PrimType itype = (stype == PTY_f32) ? PTY_i32 : PTY_i64;
3043         RegOperand &regOpnd = LoadIntoRegister(*newOpnd0, itype);
3044 
3045         result = &GetOrCreateResOperand(parent, stype);
3046         MOperator mopFmov = (is64Bits ? MOP_xvmovdr : MOP_xvmovsr);
3047         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopFmov, *result, regOpnd));
3048     }
3049     return result;
3050 }
3051 
SelectFloatConst(MIRFloatConst & floatConst,const BaseNode & parent)3052 Operand *AArch64CGFunc::SelectFloatConst(MIRFloatConst &floatConst, const BaseNode &parent)
3053 {
3054     PrimType stype = floatConst.GetType().GetPrimType();
3055     int32 val = floatConst.GetIntValue();
3056     /* according to aarch64 encoding format, convert int to float expression */
3057     return HandleFmovImm(stype, val, floatConst, parent);
3058 }
3059 
SelectDoubleConst(MIRDoubleConst & doubleConst,const BaseNode & parent)3060 Operand *AArch64CGFunc::SelectDoubleConst(MIRDoubleConst &doubleConst, const BaseNode &parent)
3061 {
3062     PrimType stype = doubleConst.GetType().GetPrimType();
3063     int64 val = doubleConst.GetIntValue();
3064     /* according to aarch64 encoding format, convert int to float expression */
3065     return HandleFmovImm(stype, val, doubleConst, parent);
3066 }
3067 
3068 template <typename T>
SelectStrLiteral(T & c,AArch64CGFunc & cgFunc)3069 Operand *SelectStrLiteral(T &c, AArch64CGFunc &cgFunc)
3070 {
3071     std::string labelStr;
3072     if (c.GetKind() == kConstStrConst) {
3073         labelStr += ".LUstr_";
3074     } else if (c.GetKind() == kConstStr16Const) {
3075         labelStr += ".LUstr16_";
3076     } else {
3077         CHECK_FATAL(false, "Unsupported literal type");
3078     }
3079     labelStr += std::to_string(c.GetValue());
3080 
3081     MIRSymbol *labelSym =
3082         GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(labelStr));
3083     if (labelSym == nullptr) {
3084         labelSym = cgFunc.GetMirModule().GetMIRBuilder()->CreateGlobalDecl(labelStr, c.GetType());
3085         labelSym->SetStorageClass(kScFstatic);
3086         labelSym->SetSKind(kStConst);
3087         /* c may be local, we need a global node here */
3088         labelSym->SetKonst(cgFunc.NewMirConst(c));
3089     }
3090 
3091     if (c.GetPrimType() == PTY_ptr) {
3092         StImmOperand &stOpnd = cgFunc.CreateStImmOperand(*labelSym, 0, 0);
3093         RegOperand &addrOpnd = cgFunc.CreateRegisterOperandOfType(PTY_a64);
3094         cgFunc.SelectAddrof(addrOpnd, stOpnd);
3095         return &addrOpnd;
3096     }
3097     CHECK_FATAL(false, "Unsupported const string type");
3098     return nullptr;
3099 }
3100 
SelectStrConst(MIRStrConst & strConst)3101 Operand *AArch64CGFunc::SelectStrConst(MIRStrConst &strConst)
3102 {
3103     return SelectStrLiteral(strConst, *this);
3104 }
3105 
SelectStr16Const(MIRStr16Const & str16Const)3106 Operand *AArch64CGFunc::SelectStr16Const(MIRStr16Const &str16Const)
3107 {
3108     return SelectStrLiteral(str16Const, *this);
3109 }
3110 
AppendInstructionTo(Insn & i,CGFunc & f)3111 static inline void AppendInstructionTo(Insn &i, CGFunc &f)
3112 {
3113     f.GetCurBB()->AppendInsn(i);
3114 }
3115 
3116 /*
3117  * Returns the number of leading 0-bits in x, starting at the most significant bit position.
3118  * If x is 0, the result is -1.
3119  */
GetHead0BitNum(int64 val)3120 static int32 GetHead0BitNum(int64 val)
3121 {
3122     uint32 bitNum = 0;
3123     for (; bitNum < k64BitSize; bitNum++) {
3124         if ((0x8000000000000000ULL >> static_cast<uint32>(bitNum)) & static_cast<uint64>(val)) {
3125             break;
3126         }
3127     }
3128     if (bitNum == k64BitSize) {
3129         return -1;
3130     }
3131     return bitNum;
3132 }
3133 
3134 /*
3135  * Returns the number of trailing 0-bits in x, starting at the least significant bit position.
3136  * If x is 0, the result is -1.
3137  */
GetTail0BitNum(int64 val)3138 static int32 GetTail0BitNum(int64 val)
3139 {
3140     uint32 bitNum = 0;
3141     for (; bitNum < k64BitSize; bitNum++) {
3142         if ((static_cast<uint64>(1) << static_cast<uint32>(bitNum)) & static_cast<uint64>(val)) {
3143             break;
3144         }
3145     }
3146     if (bitNum == k64BitSize) {
3147         return -1;
3148     }
3149     return bitNum;
3150 }
3151 
3152 /*
3153  * If the input integer is power of 2, return log2(input)
3154  * else return -1
3155  */
GetLog2(uint64 val)3156 static inline int32 GetLog2(uint64 val)
3157 {
3158     if (__builtin_popcountll(val) == 1) {
3159         return __builtin_ffsll(static_cast<int64>(val)) - 1;
3160     }
3161     return -1;
3162 }
3163 
PickJmpInsn(Opcode brOp,Opcode cmpOp,bool isFloat,bool isSigned) const3164 MOperator AArch64CGFunc::PickJmpInsn(Opcode brOp, Opcode cmpOp, bool isFloat, bool isSigned) const
3165 {
3166     switch (cmpOp) {
3167         case OP_ne:
3168             return (brOp == OP_brtrue) ? MOP_bne : MOP_beq;
3169         case OP_eq:
3170             return (brOp == OP_brtrue) ? MOP_beq : MOP_bne;
3171         case OP_lt:
3172             return (brOp == OP_brtrue) ? (isSigned ? MOP_blt : MOP_blo)
3173                                        : (isFloat ? MOP_bpl : (isSigned ? MOP_bge : MOP_bhs));
3174         case OP_le:
3175             return (brOp == OP_brtrue) ? (isSigned ? MOP_ble : MOP_bls)
3176                                        : (isFloat ? MOP_bhi : (isSigned ? MOP_bgt : MOP_bhi));
3177         case OP_gt:
3178             return (brOp == OP_brtrue) ? (isFloat ? MOP_bgt : (isSigned ? MOP_bgt : MOP_bhi))
3179                                        : (isSigned ? MOP_ble : MOP_bls);
3180         case OP_ge:
3181             return (brOp == OP_brtrue) ? (isFloat ? MOP_bpl : (isSigned ? MOP_bge : MOP_bhs))
3182                                        : (isSigned ? MOP_blt : MOP_blo);
3183         default:
3184             CHECK_FATAL(false, "PickJmpInsn error");
3185     }
3186 }
3187 
GenerateCompareWithZeroInstruction(Opcode jmpOp,Opcode cmpOp,bool is64Bits,PrimType primType,LabelOperand & targetOpnd,Operand & opnd0)3188 bool AArch64CGFunc::GenerateCompareWithZeroInstruction(Opcode jmpOp, Opcode cmpOp, bool is64Bits, PrimType primType,
3189                                                        LabelOperand &targetOpnd, Operand &opnd0)
3190 {
3191     bool finish = true;
3192     MOperator mOpCode = MOP_undef;
3193     switch (cmpOp) {
3194         case OP_ne: {
3195             if (jmpOp == OP_brtrue) {
3196                 mOpCode = is64Bits ? MOP_xcbnz : MOP_wcbnz;
3197             } else {
3198                 mOpCode = is64Bits ? MOP_xcbz : MOP_wcbz;
3199             }
3200             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, opnd0, targetOpnd));
3201             break;
3202         }
3203         case OP_eq: {
3204             if (jmpOp == OP_brtrue) {
3205                 mOpCode = is64Bits ? MOP_xcbz : MOP_wcbz;
3206             } else {
3207                 mOpCode = is64Bits ? MOP_xcbnz : MOP_wcbnz;
3208             }
3209             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, opnd0, targetOpnd));
3210             break;
3211         }
3212         /*
3213          * TBZ/TBNZ instruction have a range of +/-32KB, need to check if the jump target is reachable in a later
3214          * phase. If the branch target is not reachable, then we change tbz/tbnz into combination of ubfx and
3215          * cbz/cbnz, which will clobber one extra register. With LSRA under O2, we can use of the reserved registers
3216          * for that purpose.
3217          */
3218         case OP_lt: {
3219             if (primType == PTY_u64 || primType == PTY_u32) {
3220                 return false;
3221             }
3222             ImmOperand &signBit =
3223                 CreateImmOperand(is64Bits ? kHighestBitOf64Bits : kHighestBitOf32Bits, k8BitSize, false);
3224             if (jmpOp == OP_brtrue) {
3225                 mOpCode = is64Bits ? MOP_xtbnz : MOP_wtbnz;
3226             } else {
3227                 mOpCode = is64Bits ? MOP_xtbz : MOP_wtbz;
3228             }
3229             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, opnd0, signBit, targetOpnd));
3230             break;
3231         }
3232         case OP_ge: {
3233             if (primType == PTY_u64 || primType == PTY_u32) {
3234                 return false;
3235             }
3236             ImmOperand &signBit =
3237                 CreateImmOperand(is64Bits ? kHighestBitOf64Bits : kHighestBitOf32Bits, k8BitSize, false);
3238             if (jmpOp == OP_brtrue) {
3239                 mOpCode = is64Bits ? MOP_xtbz : MOP_wtbz;
3240             } else {
3241                 mOpCode = is64Bits ? MOP_xtbnz : MOP_wtbnz;
3242             }
3243             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, opnd0, signBit, targetOpnd));
3244             break;
3245         }
3246         default:
3247             finish = false;
3248             break;
3249     }
3250     return finish;
3251 }
3252 
SelectIgoto(Operand * opnd0)3253 void AArch64CGFunc::SelectIgoto(Operand *opnd0)
3254 {
3255     Operand *srcOpnd = opnd0;
3256     if (opnd0->GetKind() == Operand::kOpdMem) {
3257         Operand *dst = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
3258         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xldr, *dst, *opnd0));
3259         srcOpnd = dst;
3260     }
3261     GetCurBB()->SetKind(BB::kBBIgoto);
3262     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xbr, *srcOpnd));
3263 }
3264 
SelectCondGoto(LabelOperand & targetOpnd,Opcode jmpOp,Opcode cmpOp,Operand & origOpnd0,Operand & origOpnd1,PrimType primType,bool signedCond)3265 void AArch64CGFunc::SelectCondGoto(LabelOperand &targetOpnd, Opcode jmpOp, Opcode cmpOp, Operand &origOpnd0,
3266                                    Operand &origOpnd1, PrimType primType, bool signedCond)
3267 {
3268     Operand *opnd0 = &origOpnd0;
3269     Operand *opnd1 = &origOpnd1;
3270     opnd0 = &LoadIntoRegister(origOpnd0, primType);
3271 
3272     bool is64Bits = GetPrimTypeBitSize(primType) == k64BitSize;
3273     bool isFloat = IsPrimitiveFloat(primType);
3274     Operand &rflag = GetOrCreateRflag();
3275     if (isFloat) {
3276         opnd1 = &LoadIntoRegister(origOpnd1, primType);
3277         MOperator mOp =
3278             is64Bits ? MOP_dcmperr : ((GetPrimTypeBitSize(primType) == k32BitSize) ? MOP_scmperr : MOP_hcmperr);
3279         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, rflag, *opnd0, *opnd1));
3280     } else {
3281         bool isImm = ((origOpnd1.GetKind() == Operand::kOpdImmediate) || (origOpnd1.GetKind() == Operand::kOpdOffset));
3282         if ((origOpnd1.GetKind() != Operand::kOpdRegister) && !isImm) {
3283             opnd1 = &SelectCopy(origOpnd1, primType, primType);
3284         }
3285         MOperator mOp = is64Bits ? MOP_xcmprr : MOP_wcmprr;
3286 
3287         if (isImm) {
3288             if (static_cast<ImmOperand *>(opnd1)->IsZero() &&
3289                 (Globals::GetInstance()->GetOptimLevel() > CGOptions::kLevel0)) {
3290                 bool finish = GenerateCompareWithZeroInstruction(jmpOp, cmpOp, is64Bits, primType, targetOpnd, *opnd0);
3291                 if (finish) {
3292                     return;
3293                 }
3294             }
3295 
3296             /*
3297              * aarch64 assembly takes up to 24-bits immediate, generating
3298              * either cmp or cmp with shift 12 encoding
3299              */
3300             ImmOperand *immOpnd = static_cast<ImmOperand *>(opnd1);
3301             if (immOpnd->IsInBitSize(kMaxImmVal12Bits, 0) || immOpnd->IsInBitSize(kMaxImmVal12Bits, kMaxImmVal12Bits)) {
3302                 mOp = is64Bits ? MOP_xcmpri : MOP_wcmpri;
3303             } else {
3304                 opnd1 = &SelectCopy(*opnd1, primType, primType);
3305             }
3306         }
3307         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, rflag, *opnd0, *opnd1));
3308     }
3309 
3310     bool isSigned = IsPrimitiveInteger(primType) ? IsSignedInteger(primType) : (signedCond ? true : false);
3311     MOperator jmpOperator = PickJmpInsn(jmpOp, cmpOp, isFloat, isSigned);
3312     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(jmpOperator, rflag, targetOpnd));
3313 }
3314 
3315 /*
3316  *   brtrue @label0 (ge u8 i32 (
3317  *   cmp i32 i64 (dread i64 %Reg2_J, dread i64 %Reg4_J),
3318  *   constval i32 0))
3319  *  ===>
3320  *   cmp r1, r2
3321  *   bge Cond, label0
3322  */
SelectCondSpecialCase1(CondGotoNode & stmt,BaseNode & expr)3323 void AArch64CGFunc::SelectCondSpecialCase1(CondGotoNode &stmt, BaseNode &expr)
3324 {
3325     DEBUG_ASSERT(expr.GetOpCode() == OP_cmp, "unexpect opcode");
3326     Operand *opnd0 = HandleExpr(expr, *expr.Opnd(0));
3327     Operand *opnd1 = HandleExpr(expr, *expr.Opnd(1));
3328     CompareNode *node = static_cast<CompareNode *>(&expr);
3329     bool isFloat = IsPrimitiveFloat(node->GetOpndType());
3330     opnd0 = &LoadIntoRegister(*opnd0, node->GetOpndType());
3331     /*
3332      * most of FP constants are passed as MemOperand
3333      * except 0.0 which is passed as kOpdFPImmediate
3334      */
3335     Operand::OperandType opnd1Type = opnd1->GetKind();
3336     if ((opnd1Type != Operand::kOpdImmediate) && (opnd1Type != Operand::kOpdFPImmediate) &&
3337         (opnd1Type != Operand::kOpdOffset)) {
3338         opnd1 = &LoadIntoRegister(*opnd1, node->GetOpndType());
3339     }
3340     SelectAArch64Cmp(*opnd0, *opnd1, !isFloat, GetPrimTypeBitSize(node->GetOpndType()));
3341     /* handle condgoto now. */
3342     LabelIdx labelIdx = stmt.GetOffset();
3343     BaseNode *condNode = stmt.Opnd(0);
3344     LabelOperand &targetOpnd = GetOrCreateLabelOperand(labelIdx);
3345     Opcode cmpOp = condNode->GetOpCode();
3346     PrimType pType = static_cast<CompareNode *>(condNode)->GetOpndType();
3347     isFloat = IsPrimitiveFloat(pType);
3348     Operand &rflag = GetOrCreateRflag();
3349     bool isSigned =
3350         IsPrimitiveInteger(pType) ? IsSignedInteger(pType) : (IsSignedInteger(condNode->GetPrimType()) ? true : false);
3351     MOperator jmpOp = PickJmpInsn(stmt.GetOpCode(), cmpOp, isFloat, isSigned);
3352     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(jmpOp, rflag, targetOpnd));
3353 }
3354 
3355 /*
3356  * Special case:
3357  * brfalse(ge (cmpg (op0, op1), 0) ==>
3358  * fcmp op1, op2
3359  * blo
3360  */
SelectCondSpecialCase2(const CondGotoNode & stmt,BaseNode & expr)3361 void AArch64CGFunc::SelectCondSpecialCase2(const CondGotoNode &stmt, BaseNode &expr)
3362 {
3363     auto &cmpNode = static_cast<CompareNode &>(expr);
3364     Operand *opnd0 = HandleExpr(cmpNode, *cmpNode.Opnd(0));
3365     Operand *opnd1 = HandleExpr(cmpNode, *cmpNode.Opnd(1));
3366     PrimType operandType = cmpNode.GetOpndType();
3367     opnd0 = opnd0->IsRegister() ? static_cast<RegOperand *>(opnd0) : &SelectCopy(*opnd0, operandType, operandType);
3368     Operand::OperandType opnd1Type = opnd1->GetKind();
3369     if ((opnd1Type != Operand::kOpdImmediate) && (opnd1Type != Operand::kOpdFPImmediate) &&
3370         (opnd1Type != Operand::kOpdOffset)) {
3371         opnd1 = opnd1->IsRegister() ? static_cast<RegOperand *>(opnd1) : &SelectCopy(*opnd1, operandType, operandType);
3372     }
3373 #ifdef DEBUG
3374     bool isFloat = IsPrimitiveFloat(operandType);
3375     if (!isFloat) {
3376         DEBUG_ASSERT(false, "incorrect operand types");
3377     }
3378 #endif
3379     SelectTargetFPCmpQuiet(*opnd0, *opnd1, GetPrimTypeBitSize(operandType));
3380     Operand &rFlag = GetOrCreateRflag();
3381     LabelIdx tempLabelIdx = stmt.GetOffset();
3382     LabelOperand &targetOpnd = GetOrCreateLabelOperand(tempLabelIdx);
3383     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_blo, rFlag, targetOpnd));
3384 }
3385 
SelectCondGoto(CondGotoNode & stmt,Operand & opnd0,Operand & opnd1)3386 void AArch64CGFunc::SelectCondGoto(CondGotoNode &stmt, Operand &opnd0, Operand &opnd1)
3387 {
3388     /*
3389      * handle brfalse/brtrue op, opnd0 can be a compare node or non-compare node
3390      * such as a dread for example
3391      */
3392     LabelIdx labelIdx = stmt.GetOffset();
3393     BaseNode *condNode = stmt.Opnd(0);
3394     LabelOperand &targetOpnd = GetOrCreateLabelOperand(labelIdx);
3395     Opcode cmpOp;
3396 
3397     if (opnd0.IsRegister() && (static_cast<RegOperand *>(&opnd0)->GetValidBitsNum() == 1) &&
3398         (condNode->GetOpCode() == OP_lior)) {
3399         ImmOperand &condBit = CreateImmOperand(0, k8BitSize, false);
3400         if (stmt.GetOpCode() == OP_brtrue) {
3401             GetCurBB()->AppendInsn(
3402                 GetInsnBuilder()->BuildInsn(MOP_wtbnz, static_cast<RegOperand &>(opnd0), condBit, targetOpnd));
3403         } else {
3404             GetCurBB()->AppendInsn(
3405                 GetInsnBuilder()->BuildInsn(MOP_wtbz, static_cast<RegOperand &>(opnd0), condBit, targetOpnd));
3406         }
3407         return;
3408     }
3409 
3410     PrimType pType;
3411     if (kOpcodeInfo.IsCompare(condNode->GetOpCode())) {
3412         cmpOp = condNode->GetOpCode();
3413         pType = static_cast<CompareNode *>(condNode)->GetOpndType();
3414     } else {
3415         /* not a compare node; dread for example, take its pType */
3416         cmpOp = OP_ne;
3417         pType = condNode->GetPrimType();
3418     }
3419     bool signedCond = IsSignedInteger(pType) || IsPrimitiveFloat(pType);
3420     SelectCondGoto(targetOpnd, stmt.GetOpCode(), cmpOp, opnd0, opnd1, pType, signedCond);
3421 }
3422 
SelectGoto(GotoNode & stmt)3423 void AArch64CGFunc::SelectGoto(GotoNode &stmt)
3424 {
3425     Operand &targetOpnd = GetOrCreateLabelOperand(stmt.GetOffset());
3426     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xuncond, targetOpnd));
3427     GetCurBB()->SetKind(BB::kBBGoto);
3428 }
3429 
SelectAdd(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)3430 Operand *AArch64CGFunc::SelectAdd(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
3431 {
3432     PrimType dtype = node.GetPrimType();
3433     bool isSigned = IsSignedInteger(dtype);
3434     uint32 dsize = GetPrimTypeBitSize(dtype);
3435     bool is64Bits = (dsize == k64BitSize);
3436     bool isFloat = IsPrimitiveFloat(dtype);
3437     RegOperand *resOpnd = nullptr;
3438     if (!IsPrimitiveVector(dtype)) {
3439         /* promoted type */
3440         PrimType primType =
3441             isFloat ? dtype : ((is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)));
3442         if (parent.GetOpCode() == OP_regassign) {
3443             auto &regAssignNode = static_cast<const RegassignNode &>(parent);
3444             PregIdx pregIdx = regAssignNode.GetRegIdx();
3445             if (IsSpecialPseudoRegister(pregIdx)) {
3446                 resOpnd = &GetOrCreateSpecialRegisterOperand(-pregIdx, dtype);
3447             } else {
3448                 resOpnd = &GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(pregIdx));
3449             }
3450         } else {
3451             resOpnd = &CreateRegisterOperandOfType(primType);
3452         }
3453         SelectAdd(*resOpnd, opnd0, opnd1, primType);
3454     } else {
3455         /* vector operands */
3456         resOpnd =
3457             SelectVectorBinOp(dtype, &opnd0, node.Opnd(0)->GetPrimType(), &opnd1, node.Opnd(1)->GetPrimType(), OP_add);
3458     }
3459     return resOpnd;
3460 }
3461 
SelectAdd(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)3462 void AArch64CGFunc::SelectAdd(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
3463 {
3464     Operand::OperandType opnd0Type = opnd0.GetKind();
3465     Operand::OperandType opnd1Type = opnd1.GetKind();
3466     uint32 dsize = GetPrimTypeBitSize(primType);
3467     bool is64Bits = (dsize == k64BitSize);
3468     if (opnd0Type != Operand::kOpdRegister) {
3469         /* add #imm, #imm */
3470         if (opnd1Type != Operand::kOpdRegister) {
3471             SelectAdd(resOpnd, SelectCopy(opnd0, primType, primType), opnd1, primType);
3472             return;
3473         }
3474         /* add #imm, reg */
3475         SelectAdd(resOpnd, opnd1, opnd0, primType); /* commutative */
3476         return;
3477     }
3478     /* add reg, reg */
3479     if (opnd1Type == Operand::kOpdRegister) {
3480         DEBUG_ASSERT(IsPrimitiveFloat(primType) || IsPrimitiveInteger(primType), "NYI add");
3481         MOperator mOp =
3482             IsPrimitiveFloat(primType) ? (is64Bits ? MOP_dadd : MOP_sadd) : (is64Bits ? MOP_xaddrrr : MOP_waddrrr);
3483         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
3484         return;
3485     } else if (opnd1Type == Operand::kOpdStImmediate) {
3486         CHECK_FATAL(is64Bits, "baseReg of mem in aarch64 must be 64bit size");
3487         /* add reg, reg, #:lo12:sym+offset */
3488         StImmOperand &stImmOpnd = static_cast<StImmOperand &>(opnd1);
3489         Insn &newInsn = GetInsnBuilder()->BuildInsn(MOP_xadrpl12, resOpnd, opnd0, stImmOpnd);
3490         GetCurBB()->AppendInsn(newInsn);
3491         return;
3492     } else if (!((opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset))) {
3493         /* add reg, otheregType */
3494         SelectAdd(resOpnd, opnd0, SelectCopy(opnd1, primType, primType), primType);
3495         return;
3496     } else {
3497         /* add reg, #imm */
3498         ImmOperand *immOpnd = static_cast<ImmOperand *>(&opnd1);
3499         if (immOpnd->IsNegative()) {
3500             immOpnd->Negate();
3501             SelectSub(resOpnd, opnd0, *immOpnd, primType);
3502             return;
3503         }
3504         if (immOpnd->IsInBitSize(kMaxImmVal24Bits, 0)) {
3505             /*
3506              * ADD Wd|WSP, Wn|WSP, #imm{, shift} ; 32-bit general registers
3507              * ADD Xd|SP,  Xn|SP,  #imm{, shift} ; 64-bit general registers
3508              * imm : 0 ~ 4095, shift: none, LSL #0, or LSL #12
3509              * aarch64 assembly takes up to 24-bits, if the lower 12 bits is all 0
3510              */
3511             MOperator mOpCode = MOP_undef;
3512             Operand *newOpnd0 = &opnd0;
3513             if (!(immOpnd->IsInBitSize(kMaxImmVal12Bits, 0) ||
3514                   immOpnd->IsInBitSize(kMaxImmVal12Bits, kMaxImmVal12Bits))) {
3515                 /* process higher 12 bits */
3516                 ImmOperand &immOpnd2 =
3517                     CreateImmOperand(static_cast<int64>(static_cast<uint64>(immOpnd->GetValue()) >> kMaxImmVal12Bits),
3518                                      immOpnd->GetSize(), immOpnd->IsSignedValue());
3519                 mOpCode = is64Bits ? MOP_xaddrri24 : MOP_waddrri24;
3520                 Operand *tmpRes = IsAfterRegAlloc() ? &resOpnd : &CreateRegisterOperandOfType(primType);
3521                 BitShiftOperand &shiftopnd = CreateBitShiftOperand(BitShiftOperand::kLSL, kShiftAmount12, k64BitSize);
3522                 Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, *tmpRes, opnd0, immOpnd2, shiftopnd);
3523                 GetCurBB()->AppendInsn(newInsn);
3524                 immOpnd->ModuloByPow2(static_cast<int32>(kMaxImmVal12Bits));
3525                 newOpnd0 = tmpRes;
3526             }
3527             /* process lower 12  bits */
3528             mOpCode = is64Bits ? MOP_xaddrri12 : MOP_waddrri12;
3529             Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, *newOpnd0, *immOpnd);
3530             GetCurBB()->AppendInsn(newInsn);
3531             return;
3532         }
3533         /* load into register */
3534         int64 immVal = immOpnd->GetValue();
3535         int32 tail0bitNum = GetTail0BitNum(immVal);
3536         int32 head0bitNum = GetHead0BitNum(immVal);
3537         const int32 bitNum = (k64BitSizeInt - head0bitNum) - tail0bitNum;
3538         RegOperand &regOpnd = CreateRegisterOperandOfType(primType);
3539         if (isAfterRegAlloc) {
3540             RegType regty = GetRegTyFromPrimTy(primType);
3541             uint32 bytelen = GetPrimTypeSize(primType);
3542             regOpnd = GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(R16), bytelen, regty);
3543         }
3544         regno_t regNO0 = static_cast<RegOperand &>(opnd0).GetRegisterNumber();
3545         /* addrrrs do not support sp */
3546         if (bitNum <= k16ValidBit && regNO0 != RSP) {
3547             int64 newImm = (static_cast<uint64>(immVal) >> static_cast<uint32>(tail0bitNum)) & 0xFFFF;
3548             ImmOperand &immOpnd1 = CreateImmOperand(newImm, k16BitSize, false);
3549             SelectCopyImm(regOpnd, immOpnd1, primType);
3550             uint32 mopBadd = is64Bits ? MOP_xaddrrrs : MOP_waddrrrs;
3551             int32 bitLen = is64Bits ? kBitLenOfShift64Bits : kBitLenOfShift32Bits;
3552             BitShiftOperand &bitShiftOpnd =
3553                 CreateBitShiftOperand(BitShiftOperand::kLSL, static_cast<uint32>(tail0bitNum), bitLen);
3554             Insn &newInsn = GetInsnBuilder()->BuildInsn(mopBadd, resOpnd, opnd0, regOpnd, bitShiftOpnd);
3555             GetCurBB()->AppendInsn(newInsn);
3556             return;
3557         }
3558 
3559         SelectCopyImm(regOpnd, *immOpnd, primType);
3560         MOperator mOpCode = is64Bits ? MOP_xaddrrr : MOP_waddrrr;
3561         Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, opnd0, regOpnd);
3562         GetCurBB()->AppendInsn(newInsn);
3563     }
3564 }
3565 
SelectMadd(BinaryNode & node,Operand & opndM0,Operand & opndM1,Operand & opnd1,const BaseNode & parent)3566 Operand *AArch64CGFunc::SelectMadd(BinaryNode &node, Operand &opndM0, Operand &opndM1, Operand &opnd1,
3567                                    const BaseNode &parent)
3568 {
3569     PrimType dtype = node.GetPrimType();
3570     bool isSigned = IsSignedInteger(dtype);
3571     uint32 dsize = GetPrimTypeBitSize(dtype);
3572     bool is64Bits = (dsize == k64BitSize);
3573     /* promoted type */
3574     PrimType primType = is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32);
3575     RegOperand &resOpnd = GetOrCreateResOperand(parent, primType);
3576     SelectMadd(resOpnd, opndM0, opndM1, opnd1, primType);
3577     return &resOpnd;
3578 }
3579 
SelectMadd(Operand & resOpnd,Operand & opndM0,Operand & opndM1,Operand & opnd1,PrimType primType)3580 void AArch64CGFunc::SelectMadd(Operand &resOpnd, Operand &opndM0, Operand &opndM1, Operand &opnd1, PrimType primType)
3581 {
3582     Operand::OperandType opndM0Type = opndM0.GetKind();
3583     Operand::OperandType opndM1Type = opndM1.GetKind();
3584     Operand::OperandType opnd1Type = opnd1.GetKind();
3585     uint32 dsize = GetPrimTypeBitSize(primType);
3586     bool is64Bits = (dsize == k64BitSize);
3587 
3588     if (opndM0Type != Operand::kOpdRegister) {
3589         SelectMadd(resOpnd, SelectCopy(opndM0, primType, primType), opndM1, opnd1, primType);
3590         return;
3591     } else if (opndM1Type != Operand::kOpdRegister) {
3592         SelectMadd(resOpnd, opndM0, SelectCopy(opndM1, primType, primType), opnd1, primType);
3593         return;
3594     } else if (opnd1Type != Operand::kOpdRegister) {
3595         SelectMadd(resOpnd, opndM0, opndM1, SelectCopy(opnd1, primType, primType), primType);
3596         return;
3597     }
3598 
3599     DEBUG_ASSERT(IsPrimitiveInteger(primType), "NYI MAdd");
3600     MOperator mOp = is64Bits ? MOP_xmaddrrrr : MOP_wmaddrrrr;
3601     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opndM0, opndM1, opnd1));
3602 }
3603 
SelectCGArrayElemAdd(BinaryNode & node,const BaseNode & parent)3604 Operand &AArch64CGFunc::SelectCGArrayElemAdd(BinaryNode &node, const BaseNode &parent)
3605 {
3606     BaseNode *opnd0 = node.Opnd(0);
3607     BaseNode *opnd1 = node.Opnd(1);
3608     DEBUG_ASSERT(opnd1->GetOpCode() == OP_constval, "Internal error, opnd1->op should be OP_constval.");
3609 
3610     switch (opnd0->op) {
3611         case OP_regread: {
3612             RegreadNode *regreadNode = static_cast<RegreadNode *>(opnd0);
3613             return *SelectRegread(*regreadNode);
3614         }
3615         case OP_addrof: {
3616             AddrofNode *addrofNode = static_cast<AddrofNode *>(opnd0);
3617             CHECK_NULL_FATAL(mirModule.CurFunction());
3618             CHECK_NULL_FATAL(mirModule.CurFunction()->GetLocalOrGlobalSymbol(addrofNode->GetStIdx()));
3619             MIRSymbol &symbol = *mirModule.CurFunction()->GetLocalOrGlobalSymbol(addrofNode->GetStIdx());
3620             DEBUG_ASSERT(addrofNode->GetFieldID() == 0, "For debug SelectCGArrayElemAdd.");
3621 
3622             Operand &result = GetOrCreateResOperand(parent, PTY_a64);
3623 
3624             /* OP_constval */
3625             ConstvalNode *constvalNode = static_cast<ConstvalNode *>(opnd1);
3626             MIRConst *mirConst = constvalNode->GetConstVal();
3627             MIRIntConst *mirIntConst = static_cast<MIRIntConst *>(mirConst);
3628             SelectAddrof(result, CreateStImmOperand(symbol, mirIntConst->GetExtValue(), 0));
3629 
3630             return result;
3631         }
3632         default:
3633             CHECK_FATAL(0, "Internal error, cannot handle opnd0.");
3634     }
3635 }
3636 
SelectSub(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)3637 void AArch64CGFunc::SelectSub(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
3638 {
3639     Operand::OperandType opnd1Type = opnd1.GetKind();
3640     uint32 dsize = GetPrimTypeBitSize(primType);
3641     bool is64Bits = (dsize == k64BitSize);
3642     bool isFloat = IsPrimitiveFloat(primType);
3643     Operand *opnd0Bak = &LoadIntoRegister(opnd0, primType);
3644     if (opnd1Type == Operand::kOpdRegister) {
3645         MOperator mOp = isFloat ? (is64Bits ? MOP_dsub : MOP_ssub) : (is64Bits ? MOP_xsubrrr : MOP_wsubrrr);
3646         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, *opnd0Bak, opnd1));
3647         return;
3648     }
3649 
3650     if ((opnd1Type != Operand::kOpdImmediate) && (opnd1Type != Operand::kOpdOffset)) {
3651         SelectSub(resOpnd, *opnd0Bak, SelectCopy(opnd1, primType, primType), primType);
3652         return;
3653     }
3654 
3655     ImmOperand *immOpnd = static_cast<ImmOperand *>(&opnd1);
3656     if (immOpnd->IsNegative()) {
3657         immOpnd->Negate();
3658         SelectAdd(resOpnd, *opnd0Bak, *immOpnd, primType);
3659         return;
3660     }
3661 
3662     int64 higher12BitVal = static_cast<int64>(static_cast<uint64>(immOpnd->GetValue()) >> kMaxImmVal12Bits);
3663     if (immOpnd->IsInBitSize(kMaxImmVal24Bits, 0) && higher12BitVal + 1 <= kMaxPimm8) {
3664         /*
3665          * SUB Wd|WSP, Wn|WSP, #imm{, shift} ; 32-bit general registers
3666          * SUB Xd|SP,  Xn|SP,  #imm{, shift} ; 64-bit general registers
3667          * imm : 0 ~ 4095, shift: none, LSL #0, or LSL #12
3668          * aarch64 assembly takes up to 24-bits, if the lower 12 bits is all 0
3669          * large offset is treated as sub (higher 12 bits + 4096) + add
3670          * it gives opportunities for combining add + ldr due to the characteristics of aarch64's load/store
3671          */
3672         MOperator mOpCode = MOP_undef;
3673         bool isSplitSub = false;
3674         if (!(immOpnd->IsInBitSize(kMaxImmVal12Bits, 0) || immOpnd->IsInBitSize(kMaxImmVal12Bits, kMaxImmVal12Bits))) {
3675             isSplitSub = true;
3676             /* process higher 12 bits */
3677             ImmOperand &immOpnd2 = CreateImmOperand(higher12BitVal + 1, immOpnd->GetSize(), immOpnd->IsSignedValue());
3678 
3679             mOpCode = is64Bits ? MOP_xsubrri24 : MOP_wsubrri24;
3680             BitShiftOperand &shiftopnd = CreateBitShiftOperand(BitShiftOperand::kLSL, kShiftAmount12, k64BitSize);
3681             Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, *opnd0Bak, immOpnd2, shiftopnd);
3682             GetCurBB()->AppendInsn(newInsn);
3683             immOpnd->ModuloByPow2(static_cast<int64>(kMaxImmVal12Bits));
3684             immOpnd->SetValue(static_cast<int64>(kMax12UnsignedImm) - immOpnd->GetValue());
3685             opnd0Bak = &resOpnd;
3686         }
3687         /* process lower 12 bits */
3688         mOpCode = isSplitSub ? (is64Bits ? MOP_xaddrri12 : MOP_waddrri12) : (is64Bits ? MOP_xsubrri12 : MOP_wsubrri12);
3689         Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, *opnd0Bak, *immOpnd);
3690         GetCurBB()->AppendInsn(newInsn);
3691         return;
3692     }
3693 
3694     /* load into register */
3695     int64 immVal = immOpnd->GetValue();
3696     int32 tail0bitNum = GetTail0BitNum(immVal);
3697     int32 head0bitNum = GetHead0BitNum(immVal);
3698     const int32 bitNum = (k64BitSizeInt - head0bitNum) - tail0bitNum;
3699     RegOperand &regOpnd = CreateRegisterOperandOfType(primType);
3700     if (isAfterRegAlloc) {
3701         RegType regty = GetRegTyFromPrimTy(primType);
3702         uint32 bytelen = GetPrimTypeSize(primType);
3703         regOpnd = GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(R16), bytelen, regty);
3704     }
3705 
3706     if (bitNum <= k16ValidBit) {
3707         int64 newImm = (static_cast<uint64>(immVal) >> static_cast<uint32>(tail0bitNum)) & 0xFFFF;
3708         ImmOperand &immOpnd1 = CreateImmOperand(newImm, k16BitSize, false);
3709         SelectCopyImm(regOpnd, immOpnd1, primType);
3710         uint32 mopBsub = is64Bits ? MOP_xsubrrrs : MOP_wsubrrrs;
3711         int32 bitLen = is64Bits ? kBitLenOfShift64Bits : kBitLenOfShift32Bits;
3712         BitShiftOperand &bitShiftOpnd =
3713             CreateBitShiftOperand(BitShiftOperand::kLSL, static_cast<uint32>(tail0bitNum), bitLen);
3714         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBsub, resOpnd, *opnd0Bak, regOpnd, bitShiftOpnd));
3715         return;
3716     }
3717 
3718     SelectCopyImm(regOpnd, *immOpnd, primType);
3719     MOperator mOpCode = is64Bits ? MOP_xsubrrr : MOP_wsubrrr;
3720     Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, *opnd0Bak, regOpnd);
3721     GetCurBB()->AppendInsn(newInsn);
3722 }
3723 
SelectSub(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)3724 Operand *AArch64CGFunc::SelectSub(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
3725 {
3726     PrimType dtype = node.GetPrimType();
3727     bool isSigned = IsSignedInteger(dtype);
3728     uint32 dsize = GetPrimTypeBitSize(dtype);
3729     bool is64Bits = (dsize == k64BitSize);
3730     bool isFloat = IsPrimitiveFloat(dtype);
3731     RegOperand *resOpnd = nullptr;
3732     if (!IsPrimitiveVector(dtype)) {
3733         /* promoted type */
3734         PrimType primType =
3735             isFloat ? dtype : ((is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)));
3736         resOpnd = &GetOrCreateResOperand(parent, primType);
3737         SelectSub(*resOpnd, opnd0, opnd1, primType);
3738     } else {
3739         /* vector operands */
3740         resOpnd =
3741             SelectVectorBinOp(dtype, &opnd0, node.Opnd(0)->GetPrimType(), &opnd1, node.Opnd(1)->GetPrimType(), OP_sub);
3742     }
3743     return resOpnd;
3744 }
3745 
SelectMpy(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)3746 Operand *AArch64CGFunc::SelectMpy(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
3747 {
3748     PrimType dtype = node.GetPrimType();
3749     bool isSigned = IsSignedInteger(dtype);
3750     uint32 dsize = GetPrimTypeBitSize(dtype);
3751     bool is64Bits = (dsize == k64BitSize);
3752     bool isFloat = IsPrimitiveFloat(dtype);
3753     RegOperand *resOpnd = nullptr;
3754     if (!IsPrimitiveVector(dtype)) {
3755         /* promoted type */
3756         PrimType primType =
3757             isFloat ? dtype : ((is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)));
3758         resOpnd = &GetOrCreateResOperand(parent, primType);
3759         SelectMpy(*resOpnd, opnd0, opnd1, primType);
3760     } else {
3761         resOpnd =
3762             SelectVectorBinOp(dtype, &opnd0, node.Opnd(0)->GetPrimType(), &opnd1, node.Opnd(1)->GetPrimType(), OP_mul);
3763     }
3764     return resOpnd;
3765 }
3766 
SelectMpy(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)3767 void AArch64CGFunc::SelectMpy(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
3768 {
3769     Operand::OperandType opnd0Type = opnd0.GetKind();
3770     Operand::OperandType opnd1Type = opnd1.GetKind();
3771     uint32 dsize = GetPrimTypeBitSize(primType);
3772     bool is64Bits = (dsize == k64BitSize);
3773 
3774     if (((opnd0Type == Operand::kOpdImmediate) || (opnd0Type == Operand::kOpdOffset) ||
3775          (opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset)) &&
3776         IsPrimitiveInteger(primType)) {
3777         ImmOperand *imm = ((opnd0Type == Operand::kOpdImmediate) || (opnd0Type == Operand::kOpdOffset))
3778                               ? static_cast<ImmOperand *>(&opnd0)
3779                               : static_cast<ImmOperand *>(&opnd1);
3780         Operand *otherOp =
3781             ((opnd0Type == Operand::kOpdImmediate) || (opnd0Type == Operand::kOpdOffset)) ? &opnd1 : &opnd0;
3782         int64 immValue = llabs(imm->GetValue());
3783         if (immValue != 0 && (static_cast<uint64>(immValue) & (static_cast<uint64>(immValue) - 1)) == 0) {
3784             /* immValue is 1 << n */
3785             if (otherOp->GetKind() != Operand::kOpdRegister) {
3786                 otherOp = &SelectCopy(*otherOp, primType, primType);
3787             }
3788             int64 shiftVal = __builtin_ffsll(immValue);
3789             ImmOperand &shiftNum = CreateImmOperand(shiftVal - 1, dsize, false);
3790             SelectShift(resOpnd, *otherOp, shiftNum, kShiftLeft, primType);
3791             bool reachSignBit = (is64Bits && (shiftVal == k64BitSize)) || (!is64Bits && (shiftVal == k32BitSize));
3792             if (imm->GetValue() < 0 && !reachSignBit) {
3793                 SelectNeg(resOpnd, resOpnd, primType);
3794             }
3795 
3796             return;
3797         } else if (immValue > 2) {  // immValue should larger than 2
3798             uint32 zeroNum = static_cast<uint32>(__builtin_ffsll(immValue) - 1);
3799             int64 headVal = static_cast<uint64>(immValue) >> zeroNum;
3800             /*
3801              * if (headVal - 1) & (headVal - 2) == 0, that is (immVal >> zeroNum) - 1 == 1 << n
3802              * otherOp * immVal = (otherOp * (immVal >> zeroNum) * (1 << zeroNum)
3803              * = (otherOp * ((immVal >> zeroNum) - 1) + otherOp) * (1 << zeroNum)
3804              */
3805             CHECK_FATAL(static_cast<uint64>(headVal) >= 2, "value overflow");
3806             // 2 see comment above
3807             if (((static_cast<uint64>(headVal) - 1) & (static_cast<uint64>(headVal) - 2)) == 0) {
3808                 if (otherOp->GetKind() != Operand::kOpdRegister) {
3809                     otherOp = &SelectCopy(*otherOp, primType, primType);
3810                 }
3811                 ImmOperand &shiftNum1 = CreateImmOperand(__builtin_ffsll(headVal - 1) - 1, dsize, false);
3812                 RegOperand &tmpOpnd = CreateRegisterOperandOfType(primType);
3813                 SelectShift(tmpOpnd, *otherOp, shiftNum1, kShiftLeft, primType);
3814                 SelectAdd(resOpnd, *otherOp, tmpOpnd, primType);
3815                 ImmOperand &shiftNum2 = CreateImmOperand(zeroNum, dsize, false);
3816                 SelectShift(resOpnd, resOpnd, shiftNum2, kShiftLeft, primType);
3817                 if (imm->GetValue() < 0) {
3818                     SelectNeg(resOpnd, resOpnd, primType);
3819                 }
3820 
3821                 return;
3822             }
3823         }
3824     }
3825 
3826     if ((opnd0Type != Operand::kOpdRegister) && (opnd1Type != Operand::kOpdRegister)) {
3827         SelectMpy(resOpnd, SelectCopy(opnd0, primType, primType), opnd1, primType);
3828     } else if ((opnd0Type == Operand::kOpdRegister) && (opnd1Type != Operand::kOpdRegister)) {
3829         SelectMpy(resOpnd, opnd0, SelectCopy(opnd1, primType, primType), primType);
3830     } else if ((opnd0Type != Operand::kOpdRegister) && (opnd1Type == Operand::kOpdRegister)) {
3831         SelectMpy(resOpnd, opnd1, opnd0, primType);
3832     } else {
3833         DEBUG_ASSERT(IsPrimitiveFloat(primType) || IsPrimitiveInteger(primType), "NYI Mpy");
3834         MOperator mOp =
3835             IsPrimitiveFloat(primType) ? (is64Bits ? MOP_xvmuld : MOP_xvmuls) : (is64Bits ? MOP_xmulrrr : MOP_wmulrrr);
3836         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
3837     }
3838 }
3839 
SelectDiv(Operand & resOpnd,Operand & origOpnd0,Operand & opnd1,PrimType primType)3840 void AArch64CGFunc::SelectDiv(Operand &resOpnd, Operand &origOpnd0, Operand &opnd1, PrimType primType)
3841 {
3842     Operand &opnd0 = LoadIntoRegister(origOpnd0, primType);
3843     Operand::OperandType opnd0Type = opnd0.GetKind();
3844     Operand::OperandType opnd1Type = opnd1.GetKind();
3845     uint32 dsize = GetPrimTypeBitSize(primType);
3846     bool is64Bits = (dsize == k64BitSize);
3847 
3848     if (Globals::GetInstance()->GetOptimLevel() > CGOptions::kLevel0) {
3849         if (((opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset)) &&
3850             IsSignedInteger(primType)) {
3851             ImmOperand *imm = static_cast<ImmOperand *>(&opnd1);
3852             int64 immValue = llabs(imm->GetValue());
3853             if ((immValue != 0) && (static_cast<uint64>(immValue) & (static_cast<uint64>(immValue) - 1)) == 0) {
3854                 if (immValue == 1) {
3855                     if (imm->GetValue() > 0) {
3856                         uint32 mOp = is64Bits ? MOP_xmovrr : MOP_wmovrr;
3857                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0));
3858                     } else {
3859                         SelectNeg(resOpnd, opnd0, primType);
3860                     }
3861 
3862                     return;
3863                 }
3864                 int32 shiftNumber = __builtin_ffsll(immValue) - 1;
3865                 ImmOperand &shiftNum = CreateImmOperand(shiftNumber, dsize, false);
3866                 Operand &tmpOpnd = CreateRegisterOperandOfType(primType);
3867                 SelectShift(tmpOpnd, opnd0, CreateImmOperand(dsize - 1, dsize, false), kShiftAright, primType);
3868                 uint32 mopBadd = is64Bits ? MOP_xaddrrrs : MOP_waddrrrs;
3869                 int32 bitLen = is64Bits ? kBitLenOfShift64Bits : kBitLenOfShift32Bits;
3870                 BitShiftOperand &shiftOpnd = CreateBitShiftOperand(BitShiftOperand::kLSR, dsize - shiftNumber, bitLen);
3871                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBadd, tmpOpnd, opnd0, tmpOpnd, shiftOpnd));
3872                 SelectShift(resOpnd, tmpOpnd, shiftNum, kShiftAright, primType);
3873                 if (imm->GetValue() < 0) {
3874                     SelectNeg(resOpnd, resOpnd, primType);
3875                 }
3876 
3877                 return;
3878             }
3879         } else if (((opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset)) &&
3880                    IsUnsignedInteger(primType)) {
3881             ImmOperand *imm = static_cast<ImmOperand *>(&opnd1);
3882             if (imm->GetValue() != 0) {
3883                 if ((imm->GetValue() > 0) &&
3884                     ((static_cast<uint64>(imm->GetValue()) & (static_cast<uint64>(imm->GetValue()) - 1)) == 0)) {
3885                     ImmOperand &shiftNum = CreateImmOperand(__builtin_ffsll(imm->GetValue()) - 1, dsize, false);
3886                     SelectShift(resOpnd, opnd0, shiftNum, kShiftLright, primType);
3887 
3888                     return;
3889                 } else if (imm->GetValue() < 0) {
3890                     SelectAArch64Cmp(opnd0, *imm, true, dsize);
3891                     SelectAArch64CSet(resOpnd, GetCondOperand(CC_CS), is64Bits);
3892 
3893                     return;
3894                 }
3895             }
3896         }
3897     }
3898 
3899     if (opnd0Type != Operand::kOpdRegister) {
3900         SelectDiv(resOpnd, SelectCopy(opnd0, primType, primType), opnd1, primType);
3901     } else if (opnd1Type != Operand::kOpdRegister) {
3902         SelectDiv(resOpnd, opnd0, SelectCopy(opnd1, primType, primType), primType);
3903     } else {
3904         DEBUG_ASSERT(IsPrimitiveFloat(primType) || IsPrimitiveInteger(primType), "NYI Div");
3905         MOperator mOp = IsPrimitiveFloat(primType)
3906                             ? (is64Bits ? MOP_ddivrrr : MOP_sdivrrr)
3907                             : (IsSignedInteger(primType) ? (is64Bits ? MOP_xsdivrrr : MOP_wsdivrrr)
3908                                                          : (is64Bits ? MOP_xudivrrr : MOP_wudivrrr));
3909         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
3910     }
3911 }
3912 
SelectDiv(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)3913 Operand *AArch64CGFunc::SelectDiv(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
3914 {
3915     PrimType dtype = node.GetPrimType();
3916     bool isSigned = IsSignedInteger(dtype);
3917     uint32 dsize = GetPrimTypeBitSize(dtype);
3918     bool is64Bits = (dsize == k64BitSize);
3919     bool isFloat = IsPrimitiveFloat(dtype);
3920     CHECK_FATAL(!IsPrimitiveVector(dtype), "NYI DIV vector operands");
3921     /* promoted type */
3922     PrimType primType =
3923         isFloat ? dtype : ((is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)));
3924     RegOperand &resOpnd = GetOrCreateResOperand(parent, primType);
3925     SelectDiv(resOpnd, opnd0, opnd1, primType);
3926     return &resOpnd;
3927 }
3928 
SelectRem(Operand & resOpnd,Operand & lhsOpnd,Operand & rhsOpnd,PrimType primType,bool isSigned,bool is64Bits)3929 void AArch64CGFunc::SelectRem(Operand &resOpnd, Operand &lhsOpnd, Operand &rhsOpnd, PrimType primType, bool isSigned,
3930                               bool is64Bits)
3931 {
3932     Operand &opnd0 = LoadIntoRegister(lhsOpnd, primType);
3933     Operand &opnd1 = LoadIntoRegister(rhsOpnd, primType);
3934 
3935     DEBUG_ASSERT(IsPrimitiveInteger(primType), "Wrong type for REM");
3936     /*
3937      * printf("%d \n", 29 % 7 );
3938      * -> 1
3939      * printf("%u %d \n", (unsigned)-7, (unsigned)(-7) % 7 );
3940      * -> 4294967289 4
3941      * printf("%d \n", (-7) % 7 );
3942      * -> 0
3943      * printf("%d \n", 237 % -7 );
3944      * 6->
3945      * printf("implicit i->u conversion %d \n", ((unsigned)237) % -7 );
3946      * implicit conversion 237
3947 
3948      * http://stackoverflow.com/questions/35351470/obtaining-remainder-using-single-aarch64-instruction
3949      * input: x0=dividend, x1=divisor
3950      * udiv|sdiv x2, x0, x1
3951      * msub x3, x2, x1, x0  -- multply-sub : x3 <- x0 - x2*x1
3952      * result: x2=quotient, x3=remainder
3953      *
3954      * allocate temporary register
3955      */
3956     RegOperand &temp = CreateRegisterOperandOfType(primType);
3957     /*
3958      * mov     w1, #2
3959      * sdiv    wTemp, w0, w1
3960      * msub    wRespond, wTemp, w1, w0
3961      * ========>
3962      * asr     wTemp, w0, #31
3963      * lsr     wTemp, wTemp, #31  (#30 for 4, #29 for 8, ...)
3964      * add     wRespond, w0, wTemp
3965      * and     wRespond, wRespond, #1   (#3 for 4, #7 for 8, ...)
3966      * sub     wRespond, wRespond, w2
3967      *
3968      * if divde by 2
3969      * ========>
3970      * lsr     wTemp, w0, #31
3971      * add     wRespond, w0, wTemp
3972      * and     wRespond, wRespond, #1
3973      * sub     wRespond, wRespond, w2
3974      *
3975      * for unsigned rem op, just use and
3976      */
3977     if ((Globals::GetInstance()->GetOptimLevel() >= CGOptions::kLevel2)) {
3978         ImmOperand *imm = nullptr;
3979         Insn *movImmInsn = GetCurBB()->GetLastMachineInsn();
3980         if (movImmInsn &&
3981             ((movImmInsn->GetMachineOpcode() == MOP_wmovri32) || (movImmInsn->GetMachineOpcode() == MOP_xmovri64)) &&
3982             movImmInsn->GetOperand(0).Equals(opnd1)) {
3983             /*
3984              * mov w1, #2
3985              * rem res, w0, w1
3986              */
3987             imm = static_cast<ImmOperand *>(&movImmInsn->GetOperand(kInsnSecondOpnd));
3988         } else if (opnd1.IsImmediate()) {
3989             /*
3990              * rem res, w0, #2
3991              */
3992             imm = static_cast<ImmOperand *>(&opnd1);
3993         }
3994         /* positive or negative do not have effect on the result */
3995         int64 dividor = 0;
3996         if (imm && (imm->GetValue() != LONG_MIN)) {
3997             dividor = abs(imm->GetValue());
3998         }
3999         const int64 Log2OfDividor = GetLog2(static_cast<uint64>(dividor));
4000         if ((dividor != 0) && (Log2OfDividor > 0)) {
4001             if (is64Bits) {
4002                 CHECK_FATAL(Log2OfDividor < k64BitSize, "imm out of bound");
4003                 if (isSigned) {
4004                     ImmOperand &rightShiftValue = CreateImmOperand(k64BitSize - Log2OfDividor, k64BitSize, isSigned);
4005                     if (Log2OfDividor != 1) {
4006                         /* 63->shift ALL , 32 ->32bit register */
4007                         ImmOperand &rightShiftAll = CreateImmOperand(63, k64BitSize, isSigned);
4008                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xasrrri6, temp, opnd0, rightShiftAll));
4009 
4010                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xlsrrri6, temp, temp, rightShiftValue));
4011                     } else {
4012                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xlsrrri6, temp, opnd0, rightShiftValue));
4013                     }
4014                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrrr, resOpnd, opnd0, temp));
4015                     ImmOperand &remBits = CreateImmOperand(dividor - 1, k64BitSize, isSigned);
4016                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xandrri13, resOpnd, resOpnd, remBits));
4017                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xsubrrr, resOpnd, resOpnd, temp));
4018                     return;
4019                 } else if (imm && imm->GetValue() > 0) {
4020                     ImmOperand &remBits = CreateImmOperand(dividor - 1, k64BitSize, isSigned);
4021                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xandrri13, resOpnd, opnd0, remBits));
4022                     return;
4023                 }
4024             } else {
4025                 CHECK_FATAL(Log2OfDividor < k32BitSize, "imm out of bound");
4026                 if (isSigned) {
4027                     ImmOperand &rightShiftValue = CreateImmOperand(k32BitSize - Log2OfDividor, k32BitSize, isSigned);
4028                     if (Log2OfDividor != 1) {
4029                         /* 31->shift ALL , 32 ->32bit register */
4030                         ImmOperand &rightShiftAll = CreateImmOperand(31, k32BitSize, isSigned);
4031                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wasrrri5, temp, opnd0, rightShiftAll));
4032 
4033                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wlsrrri5, temp, temp, rightShiftValue));
4034                     } else {
4035                         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wlsrrri5, temp, opnd0, rightShiftValue));
4036                     }
4037 
4038                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_waddrrr, resOpnd, opnd0, temp));
4039                     ImmOperand &remBits = CreateImmOperand(dividor - 1, k32BitSize, isSigned);
4040                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wandrri12, resOpnd, resOpnd, remBits));
4041 
4042                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wsubrrr, resOpnd, resOpnd, temp));
4043                     return;
4044                 } else if (imm && imm->GetValue() > 0) {
4045                     ImmOperand &remBits = CreateImmOperand(dividor - 1, k32BitSize, isSigned);
4046                     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wandrri12, resOpnd, opnd0, remBits));
4047                     return;
4048                 }
4049             }
4050         }
4051     }
4052 
4053     uint32 mopDiv = is64Bits ? (isSigned ? MOP_xsdivrrr : MOP_xudivrrr) : (isSigned ? MOP_wsdivrrr : MOP_wudivrrr);
4054     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopDiv, temp, opnd0, opnd1));
4055 
4056     uint32 mopSub = is64Bits ? MOP_xmsubrrrr : MOP_wmsubrrrr;
4057     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopSub, resOpnd, temp, opnd1, opnd0));
4058 }
4059 
SelectRem(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4060 Operand *AArch64CGFunc::SelectRem(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4061 {
4062     PrimType dtype = node.GetPrimType();
4063     DEBUG_ASSERT(IsPrimitiveInteger(dtype), "wrong type for rem");
4064     bool isSigned = IsSignedInteger(dtype);
4065     uint32 dsize = GetPrimTypeBitSize(dtype);
4066     bool is64Bits = (dsize == k64BitSize);
4067     CHECK_FATAL(!IsPrimitiveVector(dtype), "NYI DIV vector operands");
4068 
4069     /* promoted type */
4070     PrimType primType = ((is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)));
4071     RegOperand &resOpnd = GetOrCreateResOperand(parent, primType);
4072     SelectRem(resOpnd, opnd0, opnd1, primType, isSigned, is64Bits);
4073     return &resOpnd;
4074 }
4075 
SelectLand(BinaryNode & node,Operand & lhsOpnd,Operand & rhsOpnd,const BaseNode & parent)4076 Operand *AArch64CGFunc::SelectLand(BinaryNode &node, Operand &lhsOpnd, Operand &rhsOpnd, const BaseNode &parent)
4077 {
4078     PrimType primType = node.GetPrimType();
4079     DEBUG_ASSERT(IsPrimitiveInteger(primType), "Land should be integer type");
4080     bool is64Bits = (GetPrimTypeBitSize(primType) == k64BitSize);
4081     RegOperand &resOpnd = GetOrCreateResOperand(parent, is64Bits ? PTY_u64 : PTY_u32);
4082     /*
4083      * OP0 band Op1
4084      * cmp  OP0, 0     # compare X0 with 0, sets Z bit
4085      * ccmp OP1, 0, 4 //==0100b, ne     # if(OP0!=0) cmp Op1 and 0, else NZCV <- 0100 makes OP0==0
4086      * cset RES, ne     # if Z==1(i.e., OP0==0||OP1==0) RES<-0, RES<-1
4087      */
4088     Operand &opnd0 = LoadIntoRegister(lhsOpnd, primType);
4089     SelectAArch64Cmp(opnd0, CreateImmOperand(0, primType, false), true, GetPrimTypeBitSize(primType));
4090     Operand &opnd1 = LoadIntoRegister(rhsOpnd, primType);
4091     constexpr int64 immValue4 = 4;  // integer as comment above
4092     SelectAArch64CCmp(opnd1, CreateImmOperand(0, primType, false), CreateImmOperand(immValue4, PTY_u8, false),
4093                       GetCondOperand(CC_NE), is64Bits);
4094     SelectAArch64CSet(resOpnd, GetCondOperand(CC_NE), is64Bits);
4095     return &resOpnd;
4096 }
4097 
SelectLor(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent,bool parentIsBr)4098 Operand *AArch64CGFunc::SelectLor(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent,
4099                                   bool parentIsBr)
4100 {
4101     PrimType primType = node.GetPrimType();
4102     DEBUG_ASSERT(IsPrimitiveInteger(primType), "Lior should be integer type");
4103     bool is64Bits = (GetPrimTypeBitSize(primType) == k64BitSize);
4104     RegOperand &resOpnd = GetOrCreateResOperand(parent, is64Bits ? PTY_u64 : PTY_u32);
4105     /*
4106      * OP0 band Op1
4107      * cmp  OP0, 0     # compare X0 with 0, sets Z bit
4108      * ccmp OP1, 0, 0 //==0100b, eq     # if(OP0==0,eq) cmp Op1 and 0, else NZCV <- 0000 makes OP0!=0
4109      * cset RES, ne     # if Z==1(i.e., OP0==0&&OP1==0) RES<-0, RES<-1
4110      */
4111     if (parentIsBr && !is64Bits && opnd0.IsRegister() && (static_cast<RegOperand *>(&opnd0)->GetValidBitsNum() == 1) &&
4112         opnd1.IsRegister() && (static_cast<RegOperand *>(&opnd1)->GetValidBitsNum() == 1)) {
4113         uint32 mOp = MOP_wiorrrr;
4114         static_cast<RegOperand &>(resOpnd).SetValidBitsNum(1);
4115         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
4116     } else {
4117         SelectBior(resOpnd, opnd0, opnd1, primType);
4118         SelectAArch64Cmp(resOpnd, CreateImmOperand(0, primType, false), true, GetPrimTypeBitSize(primType));
4119         SelectAArch64CSet(resOpnd, GetCondOperand(CC_NE), is64Bits);
4120     }
4121     return &resOpnd;
4122 }
4123 
SelectCmpOp(Operand & resOpnd,Operand & lhsOpnd,Operand & rhsOpnd,Opcode opcode,PrimType primType,const BaseNode & parent)4124 void AArch64CGFunc::SelectCmpOp(Operand &resOpnd, Operand &lhsOpnd, Operand &rhsOpnd, Opcode opcode, PrimType primType,
4125                                 const BaseNode &parent)
4126 {
4127     uint32 dsize = resOpnd.GetSize();
4128     bool isFloat = IsPrimitiveFloat(primType);
4129     Operand &opnd0 = LoadIntoRegister(lhsOpnd, primType);
4130 
4131     /*
4132      * most of FP constants are passed as MemOperand
4133      * except 0.0 which is passed as kOpdFPImmediate
4134      */
4135     Operand::OperandType opnd1Type = rhsOpnd.GetKind();
4136     Operand *opnd1 = &rhsOpnd;
4137     if ((opnd1Type != Operand::kOpdImmediate) && (opnd1Type != Operand::kOpdFPImmediate) &&
4138         (opnd1Type != Operand::kOpdOffset)) {
4139         opnd1 = &LoadIntoRegister(rhsOpnd, primType);
4140     }
4141 
4142     bool unsignedIntegerComparison = !isFloat && !IsSignedInteger(primType);
4143     /*
4144      * OP_cmp, OP_cmpl, OP_cmpg
4145      * <cmp> OP0, OP1  ; fcmp for OP_cmpl/OP_cmpg, cmp/fcmpe for OP_cmp
4146      * CSINV RES, WZR, WZR, GE
4147      * CSINC RES, RES, WZR, LE
4148      * if OP_cmpl, CSINV RES, RES, WZR, VC (no overflow)
4149      * if OP_cmpg, CSINC RES, RES, WZR, VC (no overflow)
4150      */
4151     RegOperand &xzr = GetZeroOpnd(dsize);
4152     if ((opcode == OP_cmpl) || (opcode == OP_cmpg)) {
4153         DEBUG_ASSERT(isFloat, "incorrect operand types");
4154         SelectTargetFPCmpQuiet(opnd0, *opnd1, GetPrimTypeBitSize(primType));
4155         SelectAArch64CSINV(resOpnd, xzr, xzr, GetCondOperand(CC_GE), (dsize == k64BitSize));
4156         SelectAArch64CSINC(resOpnd, resOpnd, xzr, GetCondOperand(CC_LE), (dsize == k64BitSize));
4157         if (opcode == OP_cmpl) {
4158             SelectAArch64CSINV(resOpnd, resOpnd, xzr, GetCondOperand(CC_VC), (dsize == k64BitSize));
4159         } else {
4160             SelectAArch64CSINC(resOpnd, resOpnd, xzr, GetCondOperand(CC_VC), (dsize == k64BitSize));
4161         }
4162         return;
4163     }
4164 
4165     if (opcode == OP_cmp) {
4166         SelectAArch64Cmp(opnd0, *opnd1, !isFloat, GetPrimTypeBitSize(primType));
4167         if (unsignedIntegerComparison) {
4168             SelectAArch64CSINV(resOpnd, xzr, xzr, GetCondOperand(CC_HS), (dsize == k64BitSize));
4169             SelectAArch64CSINC(resOpnd, resOpnd, xzr, GetCondOperand(CC_LS), (dsize == k64BitSize));
4170         } else {
4171             SelectAArch64CSINV(resOpnd, xzr, xzr, GetCondOperand(CC_GE), (dsize == k64BitSize));
4172             SelectAArch64CSINC(resOpnd, resOpnd, xzr, GetCondOperand(CC_LE), (dsize == k64BitSize));
4173         }
4174         return;
4175     }
4176 
4177     // lt u8 i32 ( xxx, 0 ) => get sign bit
4178     if ((opcode == OP_lt) && opnd0.IsRegister() && opnd1->IsImmediate() &&
4179         (static_cast<ImmOperand *>(opnd1)->GetValue() == 0) && parent.GetOpCode() != OP_select && !isFloat) {
4180         bool is64Bits = (opnd0.GetSize() == k64BitSize);
4181         if (!unsignedIntegerComparison) {
4182             int32 bitLen = is64Bits ? kBitLenOfShift64Bits : kBitLenOfShift32Bits;
4183             ImmOperand &shiftNum = CreateImmOperand(is64Bits ? kHighestBitOf64Bits : kHighestBitOf32Bits,
4184                                                     static_cast<uint32>(bitLen), false);
4185             MOperator mOpCode = is64Bits ? MOP_xlsrrri6 : MOP_wlsrrri5;
4186             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, opnd0, shiftNum));
4187             return;
4188         }
4189         ImmOperand &constNum = CreateImmOperand(0, is64Bits ? k64BitSize : k32BitSize, false);
4190         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(is64Bits ? MOP_xmovri64 : MOP_wmovri32, resOpnd, constNum));
4191         return;
4192     }
4193     SelectAArch64Cmp(opnd0, *opnd1, !isFloat, GetPrimTypeBitSize(primType));
4194 
4195     ConditionCode cc = CC_EQ;
4196     // need to handle unordered situation here.
4197     switch (opcode) {
4198         case OP_eq:
4199             cc = CC_EQ;
4200             break;
4201         case OP_ne:
4202             cc = isFloat ? CC_MI : CC_NE;
4203             break;
4204         case OP_le:
4205             cc = isFloat ? CC_LS : unsignedIntegerComparison ? CC_LS : CC_LE;
4206             break;
4207         case OP_ge:
4208             cc = unsignedIntegerComparison ? CC_HS : CC_GE;
4209             break;
4210         case OP_gt:
4211             cc = unsignedIntegerComparison ? CC_HI : CC_GT;
4212             break;
4213         case OP_lt:
4214             cc = isFloat ? CC_MI : unsignedIntegerComparison ? CC_LO : CC_LT;
4215             break;
4216         default:
4217             CHECK_FATAL(false, "illegal logical operator");
4218     }
4219     SelectAArch64CSet(resOpnd, GetCondOperand(cc), (dsize == k64BitSize));
4220     if (isFloat && opcode == OP_ne) {
4221         SelectAArch64CSINC(resOpnd, resOpnd, xzr, GetCondOperand(CC_LE), (dsize == k64BitSize));
4222     }
4223 }
4224 
SelectCmpOp(CompareNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4225 Operand *AArch64CGFunc::SelectCmpOp(CompareNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4226 {
4227     RegOperand *resOpnd = nullptr;
4228     if (!IsPrimitiveVector(node.GetPrimType())) {
4229         resOpnd = &GetOrCreateResOperand(parent, node.GetPrimType());
4230         SelectCmpOp(*resOpnd, opnd0, opnd1, node.GetOpCode(), node.GetOpndType(), parent);
4231     } else {
4232         resOpnd = SelectVectorCompare(&opnd0, node.Opnd(0)->GetPrimType(), &opnd1, node.Opnd(1)->GetPrimType(),
4233                                       node.GetOpCode());
4234     }
4235     return resOpnd;
4236 }
4237 
SelectTargetFPCmpQuiet(Operand & o0,Operand & o1,uint32 dsize)4238 void AArch64CGFunc::SelectTargetFPCmpQuiet(Operand &o0, Operand &o1, uint32 dsize)
4239 {
4240     MOperator mOpCode = 0;
4241     if (o1.GetKind() == Operand::kOpdFPImmediate) {
4242         CHECK_FATAL(static_cast<ImmOperand &>(o0).GetValue() == 0, "NIY");
4243         mOpCode = (dsize == k64BitSize) ? MOP_dcmpqri : (dsize == k32BitSize) ? MOP_scmpqri : MOP_hcmpqri;
4244     } else if (o1.GetKind() == Operand::kOpdRegister) {
4245         mOpCode = (dsize == k64BitSize) ? MOP_dcmpqrr : (dsize == k32BitSize) ? MOP_scmpqrr : MOP_hcmpqrr;
4246     } else {
4247         CHECK_FATAL(false, "unsupported operand type");
4248     }
4249     Operand &rflag = GetOrCreateRflag();
4250     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, rflag, o0, o1));
4251 }
4252 
SelectAArch64Cmp(Operand & o0,Operand & o1,bool isIntType,uint32 dsize)4253 void AArch64CGFunc::SelectAArch64Cmp(Operand &o0, Operand &o1, bool isIntType, uint32 dsize)
4254 {
4255     MOperator mOpCode = 0;
4256     Operand *newO1 = &o1;
4257     if (isIntType) {
4258         if ((o1.GetKind() == Operand::kOpdImmediate) || (o1.GetKind() == Operand::kOpdOffset)) {
4259             ImmOperand *immOpnd = static_cast<ImmOperand *>(&o1);
4260             /*
4261              * imm : 0 ~ 4095, shift: none, LSL #0, or LSL #12
4262              * aarch64 assembly takes up to 24-bits, if the lower 12 bits is all 0
4263              */
4264             if (immOpnd->IsInBitSize(kMaxImmVal12Bits, 0) || immOpnd->IsInBitSize(kMaxImmVal12Bits, kMaxImmVal12Bits)) {
4265                 mOpCode = (dsize == k64BitSize) ? MOP_xcmpri : MOP_wcmpri;
4266             } else {
4267                 /* load into register */
4268                 PrimType ptype = (dsize == k64BitSize) ? PTY_i64 : PTY_i32;
4269                 newO1 = &SelectCopy(o1, ptype, ptype);
4270                 mOpCode = (dsize == k64BitSize) ? MOP_xcmprr : MOP_wcmprr;
4271             }
4272         } else if (o1.GetKind() == Operand::kOpdRegister) {
4273             mOpCode = (dsize == k64BitSize) ? MOP_xcmprr : MOP_wcmprr;
4274         } else {
4275             CHECK_FATAL(false, "unsupported operand type");
4276         }
4277     } else { /* float */
4278         if (o1.GetKind() == Operand::kOpdFPImmediate) {
4279             CHECK_FATAL(static_cast<ImmOperand &>(o1).GetValue() == 0, "NIY");
4280             mOpCode = (dsize == k64BitSize) ? MOP_dcmperi : ((dsize == k32BitSize) ? MOP_scmperi : MOP_hcmperi);
4281         } else if (o1.GetKind() == Operand::kOpdRegister) {
4282             mOpCode = (dsize == k64BitSize) ? MOP_dcmperr : ((dsize == k32BitSize) ? MOP_scmperr : MOP_hcmperr);
4283         } else {
4284             CHECK_FATAL(false, "unsupported operand type");
4285         }
4286     }
4287     DEBUG_ASSERT(mOpCode != 0, "mOpCode undefined");
4288     Operand &rflag = GetOrCreateRflag();
4289     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, rflag, o0, *newO1));
4290 }
4291 
SelectAArch64CCmp(Operand & o,Operand & i,Operand & nzcv,CondOperand & cond,bool is64Bits)4292 void AArch64CGFunc::SelectAArch64CCmp(Operand &o, Operand &i, Operand &nzcv, CondOperand &cond, bool is64Bits)
4293 {
4294     uint32 mOpCode = is64Bits ? MOP_xccmpriic : MOP_wccmpriic;
4295     Operand &rflag = GetOrCreateRflag();
4296     std::vector<Operand *> opndVec;
4297     opndVec.push_back(&rflag);
4298     opndVec.push_back(&o);
4299     opndVec.push_back(&i);
4300     opndVec.push_back(&nzcv);
4301     opndVec.push_back(&cond);
4302     opndVec.push_back(&rflag);
4303     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, opndVec));
4304 }
4305 
SelectAArch64CSet(Operand & r,CondOperand & cond,bool is64Bits)4306 void AArch64CGFunc::SelectAArch64CSet(Operand &r, CondOperand &cond, bool is64Bits)
4307 {
4308     MOperator mOpCode = is64Bits ? MOP_xcsetrc : MOP_wcsetrc;
4309     Operand &rflag = GetOrCreateRflag();
4310     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, r, cond, rflag));
4311 }
4312 
SelectAArch64CSINV(Operand & res,Operand & o0,Operand & o1,CondOperand & cond,bool is64Bits)4313 void AArch64CGFunc::SelectAArch64CSINV(Operand &res, Operand &o0, Operand &o1, CondOperand &cond, bool is64Bits)
4314 {
4315     MOperator mOpCode = is64Bits ? MOP_xcsinvrrrc : MOP_wcsinvrrrc;
4316     Operand &rflag = GetOrCreateRflag();
4317     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, res, o0, o1, cond, rflag));
4318 }
4319 
SelectAArch64CSINC(Operand & res,Operand & o0,Operand & o1,CondOperand & cond,bool is64Bits)4320 void AArch64CGFunc::SelectAArch64CSINC(Operand &res, Operand &o0, Operand &o1, CondOperand &cond, bool is64Bits)
4321 {
4322     MOperator mOpCode = is64Bits ? MOP_xcsincrrrc : MOP_wcsincrrrc;
4323     Operand &rflag = GetOrCreateRflag();
4324     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, res, o0, o1, cond, rflag));
4325 }
4326 
SelectBand(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4327 Operand *AArch64CGFunc::SelectBand(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4328 {
4329     return SelectRelationOperator(kAND, node, opnd0, opnd1, parent);
4330 }
4331 
SelectBand(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4332 void AArch64CGFunc::SelectBand(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4333 {
4334     SelectRelationOperator(kAND, resOpnd, opnd0, opnd1, primType);
4335 }
4336 
SelectRelationOperator(RelationOperator operatorCode,const BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4337 Operand *AArch64CGFunc::SelectRelationOperator(RelationOperator operatorCode, const BinaryNode &node, Operand &opnd0,
4338                                                Operand &opnd1, const BaseNode &parent)
4339 {
4340     PrimType dtype = node.GetPrimType();
4341     bool isSigned = IsSignedInteger(dtype);
4342     uint32 dsize = GetPrimTypeBitSize(dtype);
4343     bool is64Bits = (dsize == k64BitSize);
4344     RegOperand *resOpnd = nullptr;
4345     if (!IsPrimitiveVector(dtype)) {
4346         PrimType primType =
4347             is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32); /* promoted type */
4348         resOpnd = &GetOrCreateResOperand(parent, primType);
4349         SelectRelationOperator(operatorCode, *resOpnd, opnd0, opnd1, primType);
4350     } else {
4351         /* vector operations */
4352         resOpnd = SelectVectorBitwiseOp(dtype, &opnd0, node.Opnd(0)->GetPrimType(), &opnd1, node.Opnd(1)->GetPrimType(),
4353                                         (operatorCode == kAND) ? OP_band : (operatorCode == kIOR ? OP_bior : OP_bxor));
4354     }
4355     return resOpnd;
4356 }
4357 
SelectRelationMop(RelationOperator operatorCode,RelationOperatorOpndPattern opndPattern,bool is64Bits,bool isBitmaskImmediate,bool isBitNumLessThan16) const4358 MOperator AArch64CGFunc::SelectRelationMop(RelationOperator operatorCode, RelationOperatorOpndPattern opndPattern,
4359                                            bool is64Bits, bool isBitmaskImmediate, bool isBitNumLessThan16) const
4360 {
4361     MOperator mOp = MOP_undef;
4362     if (opndPattern == kRegReg) {
4363         switch (operatorCode) {
4364             case kAND:
4365                 mOp = is64Bits ? MOP_xandrrr : MOP_wandrrr;
4366                 break;
4367             case kIOR:
4368                 mOp = is64Bits ? MOP_xiorrrr : MOP_wiorrrr;
4369                 break;
4370             case kEOR:
4371                 mOp = is64Bits ? MOP_xeorrrr : MOP_weorrrr;
4372                 break;
4373             default:
4374                 break;
4375         }
4376         return mOp;
4377     }
4378     /* opndPattern == KRegImm */
4379     if (isBitmaskImmediate) {
4380         switch (operatorCode) {
4381             case kAND:
4382                 mOp = is64Bits ? MOP_xandrri13 : MOP_wandrri12;
4383                 break;
4384             case kIOR:
4385                 mOp = is64Bits ? MOP_xiorrri13 : MOP_wiorrri12;
4386                 break;
4387             case kEOR:
4388                 mOp = is64Bits ? MOP_xeorrri13 : MOP_weorrri12;
4389                 break;
4390             default:
4391                 break;
4392         }
4393         return mOp;
4394     }
4395     /* normal imm value */
4396     if (isBitNumLessThan16) {
4397         switch (operatorCode) {
4398             case kAND:
4399                 mOp = is64Bits ? MOP_xandrrrs : MOP_wandrrrs;
4400                 break;
4401             case kIOR:
4402                 mOp = is64Bits ? MOP_xiorrrrs : MOP_wiorrrrs;
4403                 break;
4404             case kEOR:
4405                 mOp = is64Bits ? MOP_xeorrrrs : MOP_weorrrrs;
4406                 break;
4407             default:
4408                 break;
4409         }
4410         return mOp;
4411     }
4412     return mOp;
4413 }
4414 
SelectRelationOperator(RelationOperator operatorCode,Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4415 void AArch64CGFunc::SelectRelationOperator(RelationOperator operatorCode, Operand &resOpnd, Operand &opnd0,
4416                                            Operand &opnd1, PrimType primType)
4417 {
4418     Operand::OperandType opnd0Type = opnd0.GetKind();
4419     Operand::OperandType opnd1Type = opnd1.GetKind();
4420     uint32 dsize = GetPrimTypeBitSize(primType);
4421     bool is64Bits = (dsize == k64BitSize);
4422     /* op #imm. #imm */
4423     if ((opnd0Type != Operand::kOpdRegister) && (opnd1Type != Operand::kOpdRegister)) {
4424         SelectRelationOperator(operatorCode, resOpnd, SelectCopy(opnd0, primType, primType), opnd1, primType);
4425         return;
4426     }
4427     /* op #imm, reg -> op reg, #imm */
4428     if ((opnd0Type != Operand::kOpdRegister) && (opnd1Type == Operand::kOpdRegister)) {
4429         SelectRelationOperator(operatorCode, resOpnd, opnd1, opnd0, primType);
4430         return;
4431     }
4432     /* op reg, reg */
4433     if ((opnd0Type == Operand::kOpdRegister) && (opnd1Type == Operand::kOpdRegister)) {
4434         DEBUG_ASSERT(IsPrimitiveInteger(primType), "NYI band");
4435         MOperator mOp = SelectRelationMop(operatorCode, kRegReg, is64Bits, false, false);
4436         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
4437         return;
4438     }
4439     /* op reg, #imm */
4440     if ((opnd0Type == Operand::kOpdRegister) && (opnd1Type != Operand::kOpdRegister)) {
4441         if (!((opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset))) {
4442             SelectRelationOperator(operatorCode, resOpnd, opnd0, SelectCopy(opnd1, primType, primType), primType);
4443             return;
4444         }
4445 
4446         ImmOperand *immOpnd = static_cast<ImmOperand *>(&opnd1);
4447         if (immOpnd->IsZero()) {
4448             if (operatorCode == kAND) {
4449                 uint32 mopMv = is64Bits ? MOP_xmovrr : MOP_wmovrr;
4450                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopMv, resOpnd, GetZeroOpnd(dsize)));
4451             } else if ((operatorCode == kIOR) || (operatorCode == kEOR)) {
4452                 SelectCopy(resOpnd, primType, opnd0, primType);
4453             }
4454         } else if ((immOpnd->IsAllOnes()) || (!is64Bits && immOpnd->IsAllOnes32bit())) {
4455             if (operatorCode == kAND) {
4456                 SelectCopy(resOpnd, primType, opnd0, primType);
4457             } else if (operatorCode == kIOR) {
4458                 uint32 mopMovn = is64Bits ? MOP_xmovnri16 : MOP_wmovnri16;
4459                 ImmOperand &src16 = CreateImmOperand(0, k16BitSize, false);
4460                 BitShiftOperand *lslOpnd = GetLogicalShiftLeftOperand(0, is64Bits);
4461                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopMovn, resOpnd, src16, *lslOpnd));
4462             } else if (operatorCode == kEOR) {
4463                 SelectMvn(resOpnd, opnd0, primType);
4464             }
4465         } else if (immOpnd->IsBitmaskImmediate()) {
4466             MOperator mOp = SelectRelationMop(operatorCode, kRegImm, is64Bits, true, false);
4467             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, opnd1));
4468         } else {
4469             int64 immVal = immOpnd->GetValue();
4470             int32 tail0BitNum = GetTail0BitNum(immVal);
4471             int32 head0BitNum = GetHead0BitNum(immVal);
4472             const int32 bitNum = (k64BitSizeInt - head0BitNum) - tail0BitNum;
4473             RegOperand &regOpnd = CreateRegisterOperandOfType(primType);
4474 
4475             if (bitNum <= k16ValidBit) {
4476                 int64 newImm = (static_cast<uint64>(immVal) >> static_cast<uint32>(tail0BitNum)) & 0xFFFF;
4477                 ImmOperand &immOpnd1 = CreateImmOperand(newImm, k32BitSize, false);
4478                 SelectCopyImm(regOpnd, immOpnd1, primType);
4479                 MOperator mOp = SelectRelationMop(operatorCode, kRegImm, is64Bits, false, true);
4480                 int32 bitLen = is64Bits ? kBitLenOfShift64Bits : kBitLenOfShift32Bits;
4481                 BitShiftOperand &shiftOpnd =
4482                     CreateBitShiftOperand(BitShiftOperand::kLSL, static_cast<uint32>(tail0BitNum), bitLen);
4483                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, regOpnd, shiftOpnd));
4484             } else {
4485                 SelectCopyImm(regOpnd, *immOpnd, primType);
4486                 MOperator mOp = SelectRelationMop(operatorCode, kRegReg, is64Bits, false, false);
4487                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0, regOpnd));
4488             }
4489         }
4490     }
4491 }
4492 
SelectBior(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4493 Operand *AArch64CGFunc::SelectBior(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4494 {
4495     return SelectRelationOperator(kIOR, node, opnd0, opnd1, parent);
4496 }
4497 
SelectBior(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4498 void AArch64CGFunc::SelectBior(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4499 {
4500     SelectRelationOperator(kIOR, resOpnd, opnd0, opnd1, primType);
4501 }
4502 
SelectMinOrMax(bool isMin,const BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4503 Operand *AArch64CGFunc::SelectMinOrMax(bool isMin, const BinaryNode &node, Operand &opnd0, Operand &opnd1,
4504                                        const BaseNode &parent)
4505 {
4506     PrimType dtype = node.GetPrimType();
4507     bool isSigned = IsSignedInteger(dtype);
4508     uint32 dsize = GetPrimTypeBitSize(dtype);
4509     bool is64Bits = (dsize == k64BitSize);
4510     bool isFloat = IsPrimitiveFloat(dtype);
4511     /* promoted type */
4512     PrimType primType = isFloat ? dtype : (is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32));
4513     RegOperand &resOpnd = GetOrCreateResOperand(parent, primType);
4514     SelectMinOrMax(isMin, resOpnd, opnd0, opnd1, primType);
4515     return &resOpnd;
4516 }
4517 
SelectMinOrMax(bool isMin,Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4518 void AArch64CGFunc::SelectMinOrMax(bool isMin, Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4519 {
4520     uint32 dsize = GetPrimTypeBitSize(primType);
4521     bool is64Bits = (dsize == k64BitSize);
4522     if (IsPrimitiveInteger(primType)) {
4523         RegOperand &regOpnd0 = LoadIntoRegister(opnd0, primType);
4524         Operand &regOpnd1 = LoadIntoRegister(opnd1, primType);
4525         SelectAArch64Cmp(regOpnd0, regOpnd1, true, dsize);
4526         Operand &newResOpnd = LoadIntoRegister(resOpnd, primType);
4527         if (isMin) {
4528             CondOperand &cc = IsSignedInteger(primType) ? GetCondOperand(CC_LT) : GetCondOperand(CC_LO);
4529             SelectAArch64Select(newResOpnd, regOpnd0, regOpnd1, cc, true, dsize);
4530         } else {
4531             CondOperand &cc = IsSignedInteger(primType) ? GetCondOperand(CC_GT) : GetCondOperand(CC_HI);
4532             SelectAArch64Select(newResOpnd, regOpnd0, regOpnd1, cc, true, dsize);
4533         }
4534     } else if (IsPrimitiveFloat(primType)) {
4535         RegOperand &regOpnd0 = LoadIntoRegister(opnd0, primType);
4536         RegOperand &regOpnd1 = LoadIntoRegister(opnd1, primType);
4537         SelectFMinFMax(resOpnd, regOpnd0, regOpnd1, is64Bits, isMin);
4538     } else {
4539         CHECK_FATAL(false, "NIY type max or min");
4540     }
4541 }
4542 
SelectMin(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4543 Operand *AArch64CGFunc::SelectMin(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4544 {
4545     return SelectMinOrMax(true, node, opnd0, opnd1, parent);
4546 }
4547 
SelectMin(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4548 void AArch64CGFunc::SelectMin(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4549 {
4550     SelectMinOrMax(true, resOpnd, opnd0, opnd1, primType);
4551 }
4552 
SelectMax(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4553 Operand *AArch64CGFunc::SelectMax(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4554 {
4555     return SelectMinOrMax(false, node, opnd0, opnd1, parent);
4556 }
4557 
SelectMax(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4558 void AArch64CGFunc::SelectMax(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4559 {
4560     SelectMinOrMax(false, resOpnd, opnd0, opnd1, primType);
4561 }
4562 
SelectFMinFMax(Operand & resOpnd,Operand & opnd0,Operand & opnd1,bool is64Bits,bool isMin)4563 void AArch64CGFunc::SelectFMinFMax(Operand &resOpnd, Operand &opnd0, Operand &opnd1, bool is64Bits, bool isMin)
4564 {
4565     uint32 mOpCode = isMin ? (is64Bits ? MOP_xfminrrr : MOP_wfminrrr) : (is64Bits ? MOP_xfmaxrrr : MOP_wfmaxrrr);
4566     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, opnd0, opnd1));
4567 }
4568 
SelectBxor(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4569 Operand *AArch64CGFunc::SelectBxor(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4570 {
4571     return SelectRelationOperator(kEOR, node, opnd0, opnd1, parent);
4572 }
4573 
SelectBxor(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)4574 void AArch64CGFunc::SelectBxor(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
4575 {
4576     SelectRelationOperator(kEOR, resOpnd, opnd0, opnd1, primType);
4577 }
4578 
SelectShift(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4579 Operand *AArch64CGFunc::SelectShift(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4580 {
4581     PrimType dtype = node.GetPrimType();
4582     bool isSigned = IsSignedInteger(dtype);
4583     uint32 dsize = GetPrimTypeBitSize(dtype);
4584     bool is64Bits = (dsize == k64BitSize);
4585     bool isFloat = IsPrimitiveFloat(dtype);
4586     RegOperand *resOpnd = nullptr;
4587     Opcode opcode = node.GetOpCode();
4588 
4589     bool isOneElemVector = false;
4590     BaseNode *expr = node.Opnd(0);
4591     if (expr->GetOpCode() == OP_dread) {
4592         MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(static_cast<DreadNode *>(expr)->GetStIdx());
4593         isOneElemVector = symbol->GetAttr(ATTR_oneelem_simd);
4594     }
4595 
4596     Operand *opd0 = &opnd0;
4597     PrimType otyp0 = expr->GetPrimType();
4598     if (IsPrimitiveVector(dtype) && opnd0.IsConstImmediate()) {
4599         opd0 = SelectVectorFromScalar(dtype, opd0, node.Opnd(0)->GetPrimType());
4600         otyp0 = dtype;
4601     }
4602 
4603     if (IsPrimitiveVector(dtype) && opnd1.IsConstImmediate()) {
4604         int64 sConst = static_cast<ImmOperand &>(opnd1).GetValue();
4605         resOpnd = SelectVectorShiftImm(dtype, opd0, &opnd1, static_cast<int32>(sConst), opcode);
4606     } else if ((IsPrimitiveVector(dtype) || isOneElemVector) && !opnd1.IsConstImmediate()) {
4607         resOpnd = SelectVectorShift(dtype, opd0, otyp0, &opnd1, node.Opnd(1)->GetPrimType(), opcode);
4608     } else {
4609         PrimType primType =
4610             isFloat ? dtype : (is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32));
4611         resOpnd = &GetOrCreateResOperand(parent, primType);
4612         ShiftDirection direct = (opcode == OP_lshr) ? kShiftLright : ((opcode == OP_ashr) ? kShiftAright : kShiftLeft);
4613         SelectShift(*resOpnd, opnd0, opnd1, direct, primType);
4614     }
4615 
4616     if (dtype == PTY_i16) {
4617         MOperator exOp = is64Bits ? MOP_xsxth64 : MOP_xsxth32;
4618         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(exOp, *resOpnd, *resOpnd));
4619     } else if (dtype == PTY_i8) {
4620         MOperator exOp = is64Bits ? MOP_xsxtb64 : MOP_xsxtb32;
4621         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(exOp, *resOpnd, *resOpnd));
4622     }
4623     return resOpnd;
4624 }
4625 
SelectRor(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4626 Operand *AArch64CGFunc::SelectRor(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4627 {
4628     PrimType dtype = node.GetPrimType();
4629     uint32 dsize = GetPrimTypeBitSize(dtype);
4630     PrimType primType = (dsize == k64BitSize) ? PTY_u64 : PTY_u32;
4631     RegOperand *resOpnd = &GetOrCreateResOperand(parent, primType);
4632     Operand *firstOpnd = &LoadIntoRegister(opnd0, primType);
4633     MOperator mopRor = (dsize == k64BitSize) ? MOP_xrorrrr : MOP_wrorrrr;
4634     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopRor, *resOpnd, *firstOpnd, opnd1));
4635     return resOpnd;
4636 }
4637 
SelectBxorShift(Operand & resOpnd,Operand * opnd0,Operand * opnd1,Operand & opnd2,PrimType primType)4638 void AArch64CGFunc::SelectBxorShift(Operand &resOpnd, Operand *opnd0, Operand *opnd1, Operand &opnd2, PrimType primType)
4639 {
4640     opnd0 = &LoadIntoRegister(*opnd0, primType);
4641     opnd1 = &LoadIntoRegister(*opnd1, primType);
4642     uint32 dsize = GetPrimTypeBitSize(primType);
4643     bool is64Bits = (dsize == k64BitSize);
4644     MOperator mopBxor = is64Bits ? MOP_xeorrrrs : MOP_weorrrrs;
4645     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBxor, resOpnd, *opnd0, *opnd1, opnd2));
4646 }
4647 
SelectShift(Operand & resOpnd,Operand & opnd0,Operand & opnd1,ShiftDirection direct,PrimType primType)4648 void AArch64CGFunc::SelectShift(Operand &resOpnd, Operand &opnd0, Operand &opnd1, ShiftDirection direct,
4649                                 PrimType primType)
4650 {
4651     Operand::OperandType opnd1Type = opnd1.GetKind();
4652     uint32 dsize = GetPrimTypeBitSize(primType);
4653     bool is64Bits = (dsize == k64BitSize);
4654     Operand *firstOpnd = &LoadIntoRegister(opnd0, primType);
4655 
4656     MOperator mopShift;
4657     if ((opnd1Type == Operand::kOpdImmediate) || (opnd1Type == Operand::kOpdOffset)) {
4658         ImmOperand *immOpnd1 = static_cast<ImmOperand *>(&opnd1);
4659         const int64 kVal = immOpnd1->GetValue();
4660         const uint32 kShiftamt = is64Bits ? kHighestBitOf64Bits : kHighestBitOf32Bits;
4661         if (kVal == 0) {
4662             SelectCopy(resOpnd, primType, *firstOpnd, primType);
4663             return;
4664         }
4665         /* e.g. a >> -1 */
4666         if ((kVal < 0) || (kVal > kShiftamt)) {
4667             SelectShift(resOpnd, *firstOpnd, SelectCopy(opnd1, primType, primType), direct, primType);
4668             return;
4669         }
4670         switch (direct) {
4671             case kShiftLeft:
4672                 mopShift = is64Bits ? MOP_xlslrri6 : MOP_wlslrri5;
4673                 break;
4674             case kShiftAright:
4675                 mopShift = is64Bits ? MOP_xasrrri6 : MOP_wasrrri5;
4676                 break;
4677             case kShiftLright:
4678                 mopShift = is64Bits ? MOP_xlsrrri6 : MOP_wlsrrri5;
4679                 break;
4680         }
4681     } else if (opnd1Type != Operand::kOpdRegister) {
4682         SelectShift(resOpnd, *firstOpnd, SelectCopy(opnd1, primType, primType), direct, primType);
4683         return;
4684     } else {
4685         switch (direct) {
4686             case kShiftLeft:
4687                 mopShift = is64Bits ? MOP_xlslrrr : MOP_wlslrrr;
4688                 break;
4689             case kShiftAright:
4690                 mopShift = is64Bits ? MOP_xasrrrr : MOP_wasrrrr;
4691                 break;
4692             case kShiftLright:
4693                 mopShift = is64Bits ? MOP_xlsrrrr : MOP_wlsrrrr;
4694                 break;
4695         }
4696     }
4697 
4698     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopShift, resOpnd, *firstOpnd, opnd1));
4699 }
4700 
SelectAbsSub(Insn & lastInsn,const UnaryNode & node,Operand & newOpnd0)4701 Operand *AArch64CGFunc::SelectAbsSub(Insn &lastInsn, const UnaryNode &node, Operand &newOpnd0)
4702 {
4703     PrimType dtyp = node.GetPrimType();
4704     bool is64Bits = (GetPrimTypeBitSize(dtyp) == k64BitSize);
4705     /* promoted type */
4706     PrimType primType = is64Bits ? (PTY_i64) : (PTY_i32);
4707     RegOperand &resOpnd = CreateRegisterOperandOfType(primType);
4708     uint32 mopCsneg = is64Bits ? MOP_xcnegrrrc : MOP_wcnegrrrc;
4709     /* ABS requires the operand be interpreted as a signed integer */
4710     CondOperand &condOpnd = GetCondOperand(CC_MI);
4711     MOperator newMop = AArch64isa::GetMopSub2Subs(lastInsn);
4712     Operand &rflag = GetOrCreateRflag();
4713     std::vector<Operand *> opndVec;
4714     opndVec.push_back(&rflag);
4715     for (uint32 i = 0; i < lastInsn.GetOperandSize(); i++) {
4716         opndVec.push_back(&lastInsn.GetOperand(i));
4717     }
4718     Insn *subsInsn = &GetInsnBuilder()->BuildInsn(newMop, opndVec);
4719     GetCurBB()->ReplaceInsn(lastInsn, *subsInsn);
4720     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopCsneg, resOpnd, newOpnd0, condOpnd, rflag));
4721     return &resOpnd;
4722 }
4723 
SelectAbs(UnaryNode & node,Operand & opnd0)4724 Operand *AArch64CGFunc::SelectAbs(UnaryNode &node, Operand &opnd0)
4725 {
4726     PrimType dtyp = node.GetPrimType();
4727     if (IsPrimitiveVector(dtyp)) {
4728         return SelectVectorAbs(dtyp, &opnd0);
4729     } else if (IsPrimitiveFloat(dtyp)) {
4730         CHECK_FATAL(GetPrimTypeBitSize(dtyp) >= k32BitSize, "We don't support hanf-word FP operands yet");
4731         bool is64Bits = (GetPrimTypeBitSize(dtyp) == k64BitSize);
4732         Operand &newOpnd0 = LoadIntoRegister(opnd0, dtyp);
4733         RegOperand &resOpnd = CreateRegisterOperandOfType(dtyp);
4734         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(is64Bits ? MOP_dabsrr : MOP_sabsrr, resOpnd, newOpnd0));
4735         return &resOpnd;
4736     } else {
4737         bool is64Bits = (GetPrimTypeBitSize(dtyp) == k64BitSize);
4738         /* promoted type */
4739         PrimType primType = is64Bits ? (PTY_i64) : (PTY_i32);
4740         Operand &newOpnd0 = LoadIntoRegister(opnd0, primType);
4741         Insn *lastInsn = GetCurBB()->GetLastMachineInsn();
4742         if (lastInsn != nullptr && AArch64isa::IsSub(*lastInsn)) {
4743             Operand &dest = lastInsn->GetOperand(kInsnFirstOpnd);
4744             Operand &opd1 = lastInsn->GetOperand(kInsnSecondOpnd);
4745             Operand &opd2 = lastInsn->GetOperand(kInsnThirdOpnd);
4746             regno_t absReg = static_cast<RegOperand &>(newOpnd0).GetRegisterNumber();
4747             if ((dest.IsRegister() && static_cast<RegOperand &>(dest).GetRegisterNumber() == absReg) ||
4748                 (opd1.IsRegister() && static_cast<RegOperand &>(opd1).GetRegisterNumber() == absReg) ||
4749                 (opd2.IsRegister() && static_cast<RegOperand &>(opd2).GetRegisterNumber() == absReg)) {
4750                 return SelectAbsSub(*lastInsn, node, newOpnd0);
4751             }
4752         }
4753         RegOperand &resOpnd = CreateRegisterOperandOfType(primType);
4754         SelectAArch64Cmp(newOpnd0, CreateImmOperand(0, is64Bits ? PTY_u64 : PTY_u32, false), true,
4755                          GetPrimTypeBitSize(dtyp));
4756         uint32 mopCsneg = is64Bits ? MOP_xcsnegrrrc : MOP_wcsnegrrrc;
4757         /* ABS requires the operand be interpreted as a signed integer */
4758         CondOperand &condOpnd = GetCondOperand(CC_GE);
4759         Operand &rflag = GetOrCreateRflag();
4760         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopCsneg, resOpnd, newOpnd0, newOpnd0, condOpnd, rflag));
4761         return &resOpnd;
4762     }
4763 }
4764 
SelectBnot(UnaryNode & node,Operand & opnd0,const BaseNode & parent)4765 Operand *AArch64CGFunc::SelectBnot(UnaryNode &node, Operand &opnd0, const BaseNode &parent)
4766 {
4767     PrimType dtype = node.GetPrimType();
4768     DEBUG_ASSERT(IsPrimitiveInteger(dtype) || IsPrimitiveVectorInteger(dtype), "bnot expect integer or NYI");
4769     uint32 bitSize = GetPrimTypeBitSize(dtype);
4770     bool is64Bits = (bitSize == k64BitSize);
4771     bool isSigned = IsSignedInteger(dtype);
4772     RegOperand *resOpnd = nullptr;
4773     if (!IsPrimitiveVector(dtype)) {
4774         /* promoted type */
4775         PrimType primType = is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32);
4776         resOpnd = &GetOrCreateResOperand(parent, primType);
4777 
4778         Operand &newOpnd0 = LoadIntoRegister(opnd0, primType);
4779 
4780         uint32 mopBnot = is64Bits ? MOP_xnotrr : MOP_wnotrr;
4781         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBnot, *resOpnd, newOpnd0));
4782         /* generate and resOpnd, resOpnd, 0x1/0xFF/0xFFFF for PTY_u1/PTY_u8/PTY_u16 */
4783         int64 immValue = 0;
4784         if (bitSize == k1BitSize) {
4785             immValue = 1;
4786         } else if (bitSize == k8BitSize) {
4787             immValue = 0xFF;
4788         } else if (bitSize == k16BitSize) {
4789             immValue = 0xFFFF;
4790         }
4791         if (immValue != 0) {
4792             ImmOperand &imm = CreateImmOperand(PTY_u32, immValue);
4793             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wandrri12, *resOpnd, *resOpnd, imm));
4794         }
4795     } else {
4796         /* vector operand */
4797         resOpnd = SelectVectorNot(dtype, &opnd0);
4798     }
4799     return resOpnd;
4800 }
4801 
SelectBswap(IntrinsicopNode & node,Operand & opnd0,const BaseNode & parent)4802 Operand *AArch64CGFunc::SelectBswap(IntrinsicopNode &node, Operand &opnd0, const BaseNode &parent)
4803 {
4804     PrimType dtype = node.GetPrimType();
4805     auto bitWidth = (GetPrimTypeBitSize(dtype));
4806     RegOperand *resOpnd = nullptr;
4807     resOpnd = &GetOrCreateResOperand(parent, dtype);
4808     Operand &newOpnd0 = LoadIntoRegister(opnd0, dtype);
4809     uint32 mopBswap = bitWidth == 64 ? MOP_xrevrr : (bitWidth == 32 ? MOP_wrevrr : MOP_wrevrr16);
4810     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBswap, *resOpnd, newOpnd0));
4811     return resOpnd;
4812 }
4813 
SelectRegularBitFieldLoad(ExtractbitsNode & node,const BaseNode & parent)4814 Operand *AArch64CGFunc::SelectRegularBitFieldLoad(ExtractbitsNode &node, const BaseNode &parent)
4815 {
4816     PrimType dtype = node.GetPrimType();
4817     bool isSigned = IsSignedInteger(dtype);
4818     uint8 bitOffset = node.GetBitsOffset();
4819     uint8 bitSize = node.GetBitsSize();
4820     bool is64Bits = (GetPrimTypeBitSize(dtype) == k64BitSize);
4821     CHECK_FATAL(!is64Bits, "dest opnd should not be 64bit");
4822     PrimType destType = GetIntegerPrimTypeBySizeAndSign(bitSize, isSigned);
4823     Operand *result =
4824         SelectIread(parent, *static_cast<IreadNode *>(node.Opnd(0)), static_cast<int>(bitOffset / k8BitSize), destType);
4825     return result;
4826 }
4827 
SelectExtractbits(ExtractbitsNode & node,Operand & srcOpnd,const BaseNode & parent)4828 Operand *AArch64CGFunc::SelectExtractbits(ExtractbitsNode &node, Operand &srcOpnd, const BaseNode &parent)
4829 {
4830     uint8 bitOffset = node.GetBitsOffset();
4831     uint8 bitSize = node.GetBitsSize();
4832     RegOperand *srcVecRegOperand = static_cast<RegOperand *>(&srcOpnd);
4833     if (srcVecRegOperand && srcVecRegOperand->IsRegister() && (srcVecRegOperand->GetSize() == k128BitSize)) {
4834         if ((bitSize == k8BitSize || bitSize == k16BitSize || bitSize == k32BitSize || bitSize == k64BitSize) &&
4835             (bitOffset % bitSize) == k0BitSize) {
4836             uint32 lane = bitOffset / bitSize;
4837             PrimType srcVecPtype;
4838             if (bitSize == k64BitSize) {
4839                 srcVecPtype = PTY_v2u64;
4840             } else if (bitSize == k32BitSize) {
4841                 srcVecPtype = PTY_v4u32;
4842             } else if (bitSize == k16BitSize) {
4843                 srcVecPtype = PTY_v8u16;
4844             } else {
4845                 srcVecPtype = PTY_v16u8;
4846             }
4847             RegOperand *resRegOperand =
4848                 SelectVectorGetElement(node.GetPrimType(), &srcOpnd, srcVecPtype, static_cast<int32>(lane));
4849             return resRegOperand;
4850         } else {
4851             CHECK_FATAL(false, "NYI");
4852         }
4853     }
4854     PrimType dtype = node.GetPrimType();
4855     RegOperand &resOpnd = GetOrCreateResOperand(parent, dtype);
4856     bool isSigned =
4857         (node.GetOpCode() == OP_sext) ? true : (node.GetOpCode() == OP_zext) ? false : IsSignedInteger(dtype);
4858     bool is64Bits = (GetPrimTypeBitSize(dtype) == k64BitSize);
4859     uint32 immWidth = is64Bits ? kMaxImmVal13Bits : kMaxImmVal12Bits;
4860     Operand &opnd0 = LoadIntoRegister(srcOpnd, dtype);
4861     if (bitOffset == 0) {
4862         if (!isSigned && (bitSize < immWidth)) {
4863             SelectBand(resOpnd, opnd0,
4864                        CreateImmOperand(static_cast<int64>((static_cast<uint64>(1) << bitSize) - 1), immWidth, false),
4865                        dtype);
4866             return &resOpnd;
4867         } else {
4868             MOperator mOp = MOP_undef;
4869             if (bitSize == k8BitSize) {
4870                 mOp = is64Bits ? (isSigned ? MOP_xsxtb64 : MOP_undef)
4871                                : (isSigned ? MOP_xsxtb32 : (opnd0.GetSize() == k32BitSize ? MOP_xuxtb32 : MOP_undef));
4872             } else if (bitSize == k16BitSize) {
4873                 mOp = is64Bits ? (isSigned ? MOP_xsxth64 : MOP_undef)
4874                                : (isSigned ? MOP_xsxth32 : (opnd0.GetSize() == k32BitSize ? MOP_xuxth32 : MOP_undef));
4875             } else if (bitSize == k32BitSize) {
4876                 mOp = is64Bits ? (isSigned ? MOP_xsxtw64 : MOP_xuxtw64) : MOP_wmovrr;
4877             }
4878             if (mOp != MOP_undef) {
4879                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0));
4880                 return &resOpnd;
4881             }
4882         }
4883     }
4884     uint32 mopBfx =
4885         is64Bits ? (isSigned ? MOP_xsbfxrri6i6 : MOP_xubfxrri6i6) : (isSigned ? MOP_wsbfxrri5i5 : MOP_wubfxrri5i5);
4886     ImmOperand &immOpnd1 = CreateImmOperand(bitOffset, k8BitSize, false);
4887     ImmOperand &immOpnd2 = CreateImmOperand(bitSize, k8BitSize, false);
4888     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBfx, resOpnd, opnd0, immOpnd1, immOpnd2));
4889     return &resOpnd;
4890 }
4891 
4892 /*
4893  *  operand fits in MOVK if
4894  *     is64Bits && bitOffset == 0, 16, 32, 48 && bSize == 16
4895  *  or is32Bits && bitOffset == 0, 16 && bSize == 16
4896  *  imm range of aarch64-movk is [0 - 65536] imm16
4897  */
IsMoveWideKeepable(int64 offsetVal,uint32 bitOffset,uint32 bitSize,bool is64Bits)4898 inline bool IsMoveWideKeepable(int64 offsetVal, uint32 bitOffset, uint32 bitSize, bool is64Bits)
4899 {
4900     DEBUG_ASSERT(is64Bits || (bitOffset < k32BitSize), "");
4901     bool isOutOfRange = offsetVal < 0;
4902     if (!isOutOfRange) {
4903         isOutOfRange = (static_cast<unsigned long int>(offsetVal) >> k16BitSize) > 0;
4904     }
4905     if (isOutOfRange) {
4906         return false;
4907     }
4908     return ((bitOffset == k0BitSize || bitOffset == k16BitSize) ||
4909             (is64Bits && (bitOffset == k32BitSize || bitOffset == k48BitSize))) &&
4910            bitSize == k16BitSize;
4911 }
4912 
4913 /* we use the fact that A ^ B ^ A == B, A ^ 0 = A */
SelectDepositBits(DepositbitsNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)4914 Operand *AArch64CGFunc::SelectDepositBits(DepositbitsNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
4915 {
4916     uint32 bitOffset = node.GetBitsOffset();
4917     uint32 bitSize = node.GetBitsSize();
4918     PrimType regType = node.GetPrimType();
4919     bool is64Bits = GetPrimTypeBitSize(regType) == k64BitSize;
4920     /*
4921      * if operand 1 is immediate and fits in MOVK, use it
4922      * MOVK Wd, #imm{, LSL #shift} ; 32-bit general registers
4923      * MOVK Xd, #imm{, LSL #shift} ; 64-bit general registers
4924      */
4925     if (opnd1.IsIntImmediate() &&
4926         IsMoveWideKeepable(static_cast<ImmOperand &>(opnd1).GetValue(), bitOffset, bitSize, is64Bits)) {
4927         RegOperand &resOpnd = GetOrCreateResOperand(parent, regType);
4928         SelectCopy(resOpnd, regType, opnd0, regType);
4929         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn((is64Bits ? MOP_xmovkri16 : MOP_wmovkri16), resOpnd, opnd1,
4930                                                            *GetLogicalShiftLeftOperand(bitOffset, is64Bits)));
4931         return &resOpnd;
4932     } else {
4933         Operand &movOpnd = LoadIntoRegister(opnd1, regType);
4934         uint32 mopBfi = is64Bits ? MOP_xbfirri6i6 : MOP_wbfirri5i5;
4935         ImmOperand &immOpnd1 = CreateImmOperand(bitOffset, k8BitSize, false);
4936         ImmOperand &immOpnd2 = CreateImmOperand(bitSize, k8BitSize, false);
4937         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopBfi, opnd0, movOpnd, immOpnd1, immOpnd2));
4938         return &opnd0;
4939     }
4940 }
4941 
SelectLnot(UnaryNode & node,Operand & srcOpnd,const BaseNode & parent)4942 Operand *AArch64CGFunc::SelectLnot(UnaryNode &node, Operand &srcOpnd, const BaseNode &parent)
4943 {
4944     PrimType dtype = node.GetPrimType();
4945     RegOperand &resOpnd = GetOrCreateResOperand(parent, dtype);
4946     bool is64Bits = (GetPrimTypeBitSize(dtype) == k64BitSize);
4947     Operand &opnd0 = LoadIntoRegister(srcOpnd, dtype);
4948     SelectAArch64Cmp(opnd0, CreateImmOperand(0, is64Bits ? PTY_u64 : PTY_u32, false), true, GetPrimTypeBitSize(dtype));
4949     SelectAArch64CSet(resOpnd, GetCondOperand(CC_EQ), is64Bits);
4950     return &resOpnd;
4951 }
4952 
SelectNeg(UnaryNode & node,Operand & opnd0,const BaseNode & parent)4953 Operand *AArch64CGFunc::SelectNeg(UnaryNode &node, Operand &opnd0, const BaseNode &parent)
4954 {
4955     PrimType dtype = node.GetPrimType();
4956     bool is64Bits = (GetPrimTypeBitSize(dtype) == k64BitSize);
4957     RegOperand *resOpnd = nullptr;
4958     if (!IsPrimitiveVector(dtype)) {
4959         PrimType primType;
4960         if (IsPrimitiveFloat(dtype)) {
4961             primType = dtype;
4962         } else {
4963             primType = is64Bits ? (PTY_i64) : (PTY_i32); /* promoted type */
4964         }
4965         resOpnd = &GetOrCreateResOperand(parent, primType);
4966         SelectNeg(*resOpnd, opnd0, primType);
4967     } else {
4968         /* vector operand */
4969         resOpnd = SelectVectorNeg(dtype, &opnd0);
4970     }
4971     return resOpnd;
4972 }
4973 
SelectNeg(Operand & dest,Operand & srcOpnd,PrimType primType)4974 void AArch64CGFunc::SelectNeg(Operand &dest, Operand &srcOpnd, PrimType primType)
4975 {
4976     Operand &opnd0 = LoadIntoRegister(srcOpnd, primType);
4977     bool is64Bits = (GetPrimTypeBitSize(primType) == k64BitSize);
4978     MOperator mOp;
4979     if (IsPrimitiveFloat(primType)) {
4980         mOp = is64Bits ? MOP_xfnegrr : MOP_wfnegrr;
4981     } else {
4982         mOp = is64Bits ? MOP_xinegrr : MOP_winegrr;
4983     }
4984     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, opnd0));
4985 }
4986 
SelectMvn(Operand & dest,Operand & src,PrimType primType)4987 void AArch64CGFunc::SelectMvn(Operand &dest, Operand &src, PrimType primType)
4988 {
4989     Operand &opnd0 = LoadIntoRegister(src, primType);
4990     bool is64Bits = (GetPrimTypeBitSize(primType) == k64BitSize);
4991     MOperator mOp;
4992     DEBUG_ASSERT(!IsPrimitiveFloat(primType), "Instruction 'mvn' do not have float version.");
4993     mOp = is64Bits ? MOP_xnotrr : MOP_wnotrr;
4994     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, opnd0));
4995 }
4996 
SelectRecip(UnaryNode & node,Operand & src,const BaseNode & parent)4997 Operand *AArch64CGFunc::SelectRecip(UnaryNode &node, Operand &src, const BaseNode &parent)
4998 {
4999     /*
5000      * fconsts s15, #112
5001      * fdivs s0, s15, s0
5002      */
5003     PrimType dtype = node.GetPrimType();
5004     if (!IsPrimitiveFloat(dtype)) {
5005         DEBUG_ASSERT(false, "should be float type");
5006         return nullptr;
5007     }
5008     Operand &opnd0 = LoadIntoRegister(src, dtype);
5009     RegOperand &resOpnd = GetOrCreateResOperand(parent, dtype);
5010     Operand *one = nullptr;
5011     if (GetPrimTypeBitSize(dtype) == k64BitSize) {
5012         MIRDoubleConst *c = memPool->New<MIRDoubleConst>(1.0, *GlobalTables::GetTypeTable().GetTypeTable().at(PTY_f64));
5013         one = SelectDoubleConst(*c, node);
5014     } else if (GetPrimTypeBitSize(dtype) == k32BitSize) {
5015         MIRFloatConst *c = memPool->New<MIRFloatConst>(1.0f, *GlobalTables::GetTypeTable().GetTypeTable().at(PTY_f32));
5016         one = SelectFloatConst(*c, node);
5017     } else {
5018         CHECK_FATAL(false, "we don't support half-precision fp operations yet");
5019     }
5020     SelectDiv(resOpnd, *one, opnd0, dtype);
5021     return &resOpnd;
5022 }
5023 
SelectSqrt(UnaryNode & node,Operand & src,const BaseNode & parent)5024 Operand *AArch64CGFunc::SelectSqrt(UnaryNode &node, Operand &src, const BaseNode &parent)
5025 {
5026     /*
5027      * gcc generates code like below for better accurate
5028      * fsqrts  s15, s0
5029      * fcmps s15, s15
5030      * fmstat
5031      * beq .L4
5032      * push  {r3, lr}
5033      * bl  sqrtf
5034      * pop {r3, pc}
5035      * .L4:
5036      * fcpys s0, s15
5037      * bx  lr
5038      */
5039     PrimType dtype = node.GetPrimType();
5040     if (!IsPrimitiveFloat(dtype)) {
5041         DEBUG_ASSERT(false, "should be float type");
5042         return nullptr;
5043     }
5044     bool is64Bits = (GetPrimTypeBitSize(dtype) == k64BitSize);
5045     Operand &opnd0 = LoadIntoRegister(src, dtype);
5046     RegOperand &resOpnd = GetOrCreateResOperand(parent, dtype);
5047     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(is64Bits ? MOP_vsqrtd : MOP_vsqrts, resOpnd, opnd0));
5048     return &resOpnd;
5049 }
5050 
SelectCvtFloat2Int(Operand & resOpnd,Operand & srcOpnd,PrimType itype,PrimType ftype)5051 void AArch64CGFunc::SelectCvtFloat2Int(Operand &resOpnd, Operand &srcOpnd, PrimType itype, PrimType ftype)
5052 {
5053     bool is64BitsFloat = (ftype == PTY_f64);
5054     MOperator mOp = 0;
5055 
5056     DEBUG_ASSERT(((ftype == PTY_f64) || (ftype == PTY_f32)), "wrong from type");
5057     Operand &opnd0 = LoadIntoRegister(srcOpnd, ftype);
5058     switch (itype) {
5059         case PTY_i32:
5060             mOp = !is64BitsFloat ? MOP_vcvtrf : MOP_vcvtrd;
5061             break;
5062         case PTY_u32:
5063         case PTY_a32:
5064             mOp = !is64BitsFloat ? MOP_vcvturf : MOP_vcvturd;
5065             break;
5066         case PTY_i64:
5067             mOp = !is64BitsFloat ? MOP_xvcvtrf : MOP_xvcvtrd;
5068             break;
5069         case PTY_u64:
5070         case PTY_a64:
5071             mOp = !is64BitsFloat ? MOP_xvcvturf : MOP_xvcvturd;
5072             break;
5073         default:
5074             CHECK_FATAL(false, "unexpected type");
5075     }
5076     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0));
5077 }
5078 
SelectCvtInt2Float(Operand & resOpnd,Operand & origOpnd0,PrimType toType,PrimType fromType)5079 void AArch64CGFunc::SelectCvtInt2Float(Operand &resOpnd, Operand &origOpnd0, PrimType toType, PrimType fromType)
5080 {
5081     DEBUG_ASSERT((toType == PTY_f32) || (toType == PTY_f64), "unexpected type");
5082     bool is64BitsFloat = (toType == PTY_f64);
5083     MOperator mOp = 0;
5084     uint32 fsize = GetPrimTypeBitSize(fromType);
5085 
5086     PrimType itype = (GetPrimTypeBitSize(fromType) == k64BitSize) ? (IsSignedInteger(fromType) ? PTY_i64 : PTY_u64)
5087                                                                   : (IsSignedInteger(fromType) ? PTY_i32 : PTY_u32);
5088 
5089     Operand *opnd0 = &LoadIntoRegister(origOpnd0, itype);
5090 
5091     /* need extension before cvt */
5092     DEBUG_ASSERT(opnd0->IsRegister(), "opnd should be a register operand");
5093     Operand *srcOpnd = opnd0;
5094     if (IsSignedInteger(fromType) && (fsize < k32BitSize)) {
5095         srcOpnd = &CreateRegisterOperandOfType(itype);
5096         mOp = (fsize == k8BitSize) ? MOP_xsxtb32 : MOP_xsxth32;
5097         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *srcOpnd, *opnd0));
5098     }
5099 
5100     switch (itype) {
5101         case PTY_i32:
5102             mOp = !is64BitsFloat ? MOP_vcvtfr : MOP_vcvtdr;
5103             break;
5104         case PTY_u32:
5105             mOp = !is64BitsFloat ? MOP_vcvtufr : MOP_vcvtudr;
5106             break;
5107         case PTY_i64:
5108             mOp = !is64BitsFloat ? MOP_xvcvtfr : MOP_xvcvtdr;
5109             break;
5110         case PTY_u64:
5111             mOp = !is64BitsFloat ? MOP_xvcvtufr : MOP_xvcvtudr;
5112             break;
5113         default:
5114             CHECK_FATAL(false, "unexpected type");
5115     }
5116     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, *srcOpnd));
5117 }
5118 
SelectIntrinsicOpWithOneParam(IntrinsicopNode & intrnNode,std::string name)5119 Operand *AArch64CGFunc::SelectIntrinsicOpWithOneParam(IntrinsicopNode &intrnNode, std::string name)
5120 {
5121     BaseNode *argexpr = intrnNode.Opnd(0);
5122     PrimType ptype = argexpr->GetPrimType();
5123     Operand *opnd = HandleExpr(intrnNode, *argexpr);
5124     if (intrnNode.GetIntrinsic() == INTRN_C_ffs) {
5125         DEBUG_ASSERT(intrnNode.GetPrimType() == PTY_i32, "Unexpect Size");
5126         return SelectAArch64ffs(*opnd, ptype);
5127     }
5128     if (opnd->IsMemoryAccessOperand()) {
5129         RegOperand &ldDest = CreateRegisterOperandOfType(ptype);
5130         Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype), ptype), ldDest, *opnd);
5131         GetCurBB()->AppendInsn(insn);
5132         opnd = &ldDest;
5133     }
5134     std::vector<Operand *> opndVec;
5135     RegOperand *dst = &CreateRegisterOperandOfType(ptype);
5136     opndVec.push_back(dst);  /* result */
5137     opndVec.push_back(opnd); /* param 0 */
5138     SelectLibCall(name, opndVec, ptype, ptype);
5139 
5140     return dst;
5141 }
5142 
SelectIntrinsicOpWithNParams(IntrinsicopNode & intrnNode,PrimType retType,const std::string & name)5143 Operand *AArch64CGFunc::SelectIntrinsicOpWithNParams(IntrinsicopNode &intrnNode, PrimType retType,
5144                                                      const std::string &name)
5145 {
5146     MapleVector<BaseNode *> argNodes = intrnNode.GetNopnd();
5147     std::vector<Operand *> opndVec;
5148     std::vector<PrimType> opndTypes;
5149     RegOperand *retOpnd = &CreateRegisterOperandOfType(retType);
5150     opndVec.push_back(retOpnd);
5151     opndTypes.push_back(retType);
5152 
5153     for (BaseNode *argexpr : argNodes) {
5154         PrimType ptype = argexpr->GetPrimType();
5155         Operand *opnd = HandleExpr(intrnNode, *argexpr);
5156         if (opnd->IsMemoryAccessOperand()) {
5157             RegOperand &ldDest = CreateRegisterOperandOfType(ptype);
5158             Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype), ptype), ldDest, *opnd);
5159             GetCurBB()->AppendInsn(insn);
5160             opnd = &ldDest;
5161         }
5162         opndVec.push_back(opnd);
5163         opndTypes.push_back(ptype);
5164     }
5165     SelectLibCallNArg(name, opndVec, opndTypes, retType, false);
5166 
5167     return retOpnd;
5168 }
5169 
5170 /* According to  gcc.target/aarch64/ffs.c */
SelectAArch64ffs(Operand & argOpnd,PrimType argType)5171 Operand *AArch64CGFunc::SelectAArch64ffs(Operand &argOpnd, PrimType argType)
5172 {
5173     RegOperand &destOpnd = LoadIntoRegister(argOpnd, argType);
5174     uint32 argSize = GetPrimTypeBitSize(argType);
5175     DEBUG_ASSERT((argSize == k64BitSize || argSize == k32BitSize), "Unexpect arg type");
5176     /* cmp */
5177     ImmOperand &zeroOpnd = CreateImmOperand(0, argSize, false);
5178     Operand &rflag = GetOrCreateRflag();
5179     GetCurBB()->AppendInsn(
5180         GetInsnBuilder()->BuildInsn(argSize == k64BitSize ? MOP_xcmpri : MOP_wcmpri, rflag, destOpnd, zeroOpnd));
5181     /* rbit */
5182     RegOperand *tempResReg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, GetPrimTypeSize(argType)));
5183     GetCurBB()->AppendInsn(
5184         GetInsnBuilder()->BuildInsn(argSize == k64BitSize ? MOP_xrbit : MOP_wrbit, *tempResReg, destOpnd));
5185     /* clz */
5186     GetCurBB()->AppendInsn(
5187         GetInsnBuilder()->BuildInsn(argSize == k64BitSize ? MOP_xclz : MOP_wclz, *tempResReg, *tempResReg));
5188     /* csincc */
5189     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(argSize == k64BitSize ? MOP_xcsincrrrc : MOP_wcsincrrrc,
5190                                                        *tempResReg, GetZeroOpnd(k32BitSize), *tempResReg,
5191                                                        GetCondOperand(CC_EQ), rflag));
5192     return tempResReg;
5193 }
5194 
SelectRoundLibCall(RoundType roundType,const TypeCvtNode & node,Operand & opnd0)5195 Operand *AArch64CGFunc::SelectRoundLibCall(RoundType roundType, const TypeCvtNode &node, Operand &opnd0)
5196 {
5197     PrimType ftype = node.FromType();
5198     PrimType rtype = node.GetPrimType();
5199     bool is64Bits = (ftype == PTY_f64);
5200     std::vector<Operand *> opndVec;
5201     RegOperand *resOpnd;
5202     if (is64Bits) {
5203         resOpnd = &GetOrCreatePhysicalRegisterOperand(D0, k64BitSize, kRegTyFloat);
5204     } else {
5205         resOpnd = &GetOrCreatePhysicalRegisterOperand(S0, k32BitSize, kRegTyFloat);
5206     }
5207     opndVec.push_back(resOpnd);
5208     RegOperand &regOpnd0 = LoadIntoRegister(opnd0, ftype);
5209     opndVec.push_back(&regOpnd0);
5210     std::string libName;
5211     if (roundType == kCeil) {
5212         libName.assign(is64Bits ? "ceil" : "ceilf");
5213     } else if (roundType == kFloor) {
5214         libName.assign(is64Bits ? "floor" : "floorf");
5215     } else {
5216         libName.assign(is64Bits ? "round" : "roundf");
5217     }
5218     SelectLibCall(libName, opndVec, ftype, rtype);
5219 
5220     return resOpnd;
5221 }
5222 
SelectRoundOperator(RoundType roundType,const TypeCvtNode & node,Operand & opnd0,const BaseNode & parent)5223 Operand *AArch64CGFunc::SelectRoundOperator(RoundType roundType, const TypeCvtNode &node, Operand &opnd0,
5224                                             const BaseNode &parent)
5225 {
5226     PrimType itype = node.GetPrimType();
5227     if ((mirModule.GetSrcLang() == kSrcLangC) && ((itype == PTY_f64) || (itype == PTY_f32))) {
5228         SelectRoundLibCall(roundType, node, opnd0);
5229     }
5230     PrimType ftype = node.FromType();
5231     DEBUG_ASSERT(((ftype == PTY_f64) || (ftype == PTY_f32)), "wrong float type");
5232     bool is64Bits = (ftype == PTY_f64);
5233     bool isFloat = (ftype == PTY_f64) || (ftype == PTY_f32);
5234     RegOperand &resOpnd = GetOrCreateResOperand(parent, itype);
5235     RegOperand &regOpnd0 = LoadIntoRegister(opnd0, ftype);
5236     MOperator mop = MOP_undef;
5237     if (roundType == kCeil) {
5238         if (isFloat) {
5239             mop = is64Bits ? MOP_dfrintprr : MOP_sfrintprr;
5240         } else {
5241             mop = is64Bits ? MOP_xvcvtps : MOP_vcvtps;
5242         }
5243     } else if (roundType == kFloor) {
5244         if (isFloat) {
5245             mop = is64Bits ? MOP_dfrintmrr : MOP_sfrintmrr;
5246         } else {
5247             mop = is64Bits ? MOP_xvcvtms : MOP_vcvtms;
5248         }
5249     } else if (roundType == kTrunc) {
5250         if (isFloat) {
5251             mop = is64Bits ? MOP_dfrintzrr : MOP_sfrintzrr;
5252         } else {
5253             CHECK_FATAL(false, "not support here!");
5254         }
5255     } else {
5256         CHECK_FATAL(!isFloat, "not support float here!");
5257         mop = is64Bits ? MOP_xvcvtas : MOP_vcvtas;
5258     }
5259     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, resOpnd, regOpnd0));
5260     return &resOpnd;
5261 }
5262 
SelectCeil(TypeCvtNode & node,Operand & opnd0,const BaseNode & parent)5263 Operand *AArch64CGFunc::SelectCeil(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent)
5264 {
5265     return SelectRoundOperator(kCeil, node, opnd0, parent);
5266 }
5267 
5268 /* float to int floor */
SelectFloor(TypeCvtNode & node,Operand & opnd0,const BaseNode & parent)5269 Operand *AArch64CGFunc::SelectFloor(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent)
5270 {
5271     return SelectRoundOperator(kFloor, node, opnd0, parent);
5272 }
5273 
SelectRound(TypeCvtNode & node,Operand & opnd0,const BaseNode & parent)5274 Operand *AArch64CGFunc::SelectRound(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent)
5275 {
5276     return SelectRoundOperator(kRound, node, opnd0, parent);
5277 }
5278 
LIsPrimitivePointer(PrimType ptype)5279 static bool LIsPrimitivePointer(PrimType ptype)
5280 {
5281     return ((ptype >= PTY_ptr) && (ptype <= PTY_a64));
5282 }
5283 
SelectRetype(TypeCvtNode & node,Operand & opnd0)5284 Operand *AArch64CGFunc::SelectRetype(TypeCvtNode &node, Operand &opnd0)
5285 {
5286     PrimType fromType = node.Opnd(0)->GetPrimType();
5287     PrimType toType = node.GetPrimType();
5288     DEBUG_ASSERT(GetPrimTypeSize(fromType) == GetPrimTypeSize(toType), "retype bit widith doesn' match");
5289     if (LIsPrimitivePointer(fromType) && LIsPrimitivePointer(toType)) {
5290         return &LoadIntoRegister(opnd0, toType);
5291     }
5292     // if source operand is in memory,
5293     // simply read it as a value of 'toType 'into the dest operand and return
5294     if (opnd0.IsMemoryAccessOperand()) {
5295         return &SelectCopy(opnd0, toType, toType);
5296     }
5297 
5298     bool isFromInt = IsPrimitiveInteger(fromType);
5299     bool is64Bits = GetPrimTypeBitSize(fromType) == k64BitSize;
5300     bool isImm = false;
5301     Operand *newOpnd0 = &opnd0;
5302     if (opnd0.IsImmediate()) {
5303         // according to aarch64 encoding format, convert int to float expression
5304         ImmOperand *imm = static_cast<ImmOperand *>(&opnd0);
5305         uint64 val = static_cast<uint64>(imm->GetValue());
5306         uint64 canRepreset = is64Bits ? (val & 0xffffffffffff) : (val & 0x7ffff);
5307         uint32 val1 = is64Bits ? (val >> 61) & 0x3 : (val >> 29) & 0x3;
5308         uint32 val2 = is64Bits ? (val >> 54) & 0xff : (val >> 25) & 0x1f;
5309         bool isSame = is64Bits ? ((val2 == 0) || (val2 == 0xff)) : ((val2 == 0) || (val2 == 0x1f));
5310         canRepreset = (canRepreset == 0) && ((val1 & 0x1) ^ ((val1 & 0x2) >> 1)) && isSame;
5311         if (IsPrimitiveInteger(fromType) && IsPrimitiveFloat(toType) && canRepreset) {
5312             uint64 temp1 = is64Bits ? (val >> 63) << 7 : (val >> 31) << 7;
5313             uint64 temp2 = is64Bits ? val >> 48 : val >> 19;
5314             int64 imm8 = (temp2 & 0x7f) | temp1;
5315             newOpnd0 = &CreateImmOperand(imm8, k8BitSize, false, kNotVary, true);
5316             isImm = true;
5317         }
5318     }
5319     if (!isImm) {
5320         bool isSigned = IsSignedInteger(fromType);
5321         PrimType itype = isFromInt ? (is64Bits ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32))
5322                                    : (is64Bits ? PTY_f64 : PTY_f32);
5323         newOpnd0 = &LoadIntoRegister(opnd0, itype);
5324     }
5325     if ((IsPrimitiveFloat(fromType) && IsPrimitiveInteger(toType)) ||
5326         (IsPrimitiveFloat(toType) && IsPrimitiveInteger(fromType))) {
5327         MOperator mopFmov =  isImm ? (is64Bits ? MOP_xdfmovri : MOP_wsfmovri)
5328                                    : (isFromInt ? (is64Bits ? MOP_xvmovdr : MOP_xvmovsr)
5329                                                 : (is64Bits ? MOP_xvmovrd : MOP_xvmovrs));
5330         RegOperand *resOpnd = &CreateRegisterOperandOfType(toType);
5331         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopFmov, *resOpnd, *newOpnd0));
5332         return resOpnd;
5333     }
5334     return newOpnd0;
5335 }
5336 
SelectCvtFloat2Float(Operand & resOpnd,Operand & srcOpnd,PrimType fromType,PrimType toType)5337 void AArch64CGFunc::SelectCvtFloat2Float(Operand &resOpnd, Operand &srcOpnd, PrimType fromType, PrimType toType)
5338 {
5339     Operand &opnd0 = LoadIntoRegister(srcOpnd, fromType);
5340     MOperator mOp = 0;
5341     switch (toType) {
5342         case PTY_f32: {
5343             CHECK_FATAL(fromType == PTY_f64, "unexpected cvt from type");
5344             mOp = MOP_xvcvtfd;
5345             break;
5346         }
5347         case PTY_f64: {
5348             CHECK_FATAL(fromType == PTY_f32, "unexpected cvt from type");
5349             mOp = MOP_xvcvtdf;
5350             break;
5351         }
5352         default:
5353             CHECK_FATAL(false, "unexpected cvt to type");
5354     }
5355 
5356     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, resOpnd, opnd0));
5357 }
5358 
5359 /*
5360  * This should be regarded only as a reference.
5361  *
5362  * C11 specification.
5363  * 6.3.1.3 Signed and unsigned integers
5364  * 1 When a value with integer type is converted to another integer
5365  *  type other than _Bool, if the value can be represented by the
5366  *  new type, it is unchanged.
5367  * 2 Otherwise, if the new type is unsigned, the value is converted
5368  *  by repeatedly adding or subtracting one more than the maximum
5369  *  value that can be represented in the new type until the value
5370  *  is in the range of the new type.60)
5371  * 3 Otherwise, the new type is signed and the value cannot be
5372  *  represented in it; either the result is implementation-defined
5373  *  or an implementation-defined signal is raised.
5374  */
SelectCvtInt2Int(const BaseNode * parent,Operand * & resOpnd,Operand * opnd0,PrimType fromType,PrimType toType)5375 void AArch64CGFunc::SelectCvtInt2Int(const BaseNode *parent, Operand *&resOpnd, Operand *opnd0, PrimType fromType,
5376                                      PrimType toType)
5377 {
5378     uint32 fsize = GetPrimTypeBitSize(fromType);
5379     if (fromType == PTY_i128 || fromType == PTY_u128) {
5380         fsize = k64BitSize;
5381     }
5382     uint32 tsize = GetPrimTypeBitSize(toType);
5383     if (toType == PTY_i128 || toType == PTY_u128) {
5384         tsize = k64BitSize;
5385     }
5386     bool isExpand = tsize > fsize;
5387     bool is64Bit = (tsize == k64BitSize);
5388     if ((parent != nullptr) && opnd0->IsIntImmediate() &&
5389         ((parent->GetOpCode() == OP_band) || (parent->GetOpCode() == OP_bior) || (parent->GetOpCode() == OP_bxor) ||
5390          (parent->GetOpCode() == OP_ashr) || (parent->GetOpCode() == OP_lshr) || (parent->GetOpCode() == OP_shl))) {
5391         ImmOperand *simm = static_cast<ImmOperand *>(opnd0);
5392         DEBUG_ASSERT(simm != nullptr, "simm is nullptr in AArch64CGFunc::SelectCvtInt2Int");
5393         bool isSign = false;
5394         int64 origValue = simm->GetValue();
5395         int64 newValue = origValue;
5396         int64 signValue = 0;
5397         if (!isExpand) {
5398             /* 64--->32 */
5399             if (fsize > tsize) {
5400                 if (IsSignedInteger(toType)) {
5401                     if (origValue < 0) {
5402                         signValue = static_cast<int64>(0xFFFFFFFFFFFFFFFFLL & (1ULL << static_cast<uint32>(tsize)));
5403                     }
5404                     newValue = static_cast<int64>(
5405                         (static_cast<uint64>(origValue) & ((1ULL << static_cast<uint32>(tsize)) - 1u)) |
5406                         static_cast<uint64>(signValue));
5407                 } else {
5408                     newValue = static_cast<uint64>(origValue) & ((1ULL << static_cast<uint32>(tsize)) - 1u);
5409                 }
5410             }
5411         }
5412         if (IsSignedInteger(toType)) {
5413             isSign = true;
5414         }
5415         resOpnd = &static_cast<Operand &>(CreateImmOperand(newValue, GetPrimTypeSize(toType) * kBitsPerByte, isSign));
5416         return;
5417     }
5418     if (isExpand) { /* Expansion */
5419         /* if cvt expr's parent is add,and,xor and some other,we can use the imm version */
5420         PrimType primType = ((fsize == k64BitSize) ? (IsSignedInteger(fromType) ? PTY_i64 : PTY_u64)
5421                                                    : (IsSignedInteger(fromType) ? PTY_i32 : PTY_u32));
5422         opnd0 = &LoadIntoRegister(*opnd0, primType);
5423 
5424         if (IsSignedInteger(fromType)) {
5425             DEBUG_ASSERT((is64Bit || (fsize == k8BitSize || fsize == k16BitSize)), "incorrect from size");
5426 
5427             MOperator mOp =
5428                 (is64Bit ? ((fsize == k8BitSize) ? MOP_xsxtb64 : ((fsize == k16BitSize) ? MOP_xsxth64 : MOP_xsxtw64))
5429                          : ((fsize == k8BitSize) ? MOP_xsxtb32 : MOP_xsxth32));
5430             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resOpnd, *opnd0));
5431         } else {
5432             /* Unsigned */
5433             auto mOp =
5434                 (is64Bit ? ((fsize == k8BitSize) ? MOP_xuxtb32 : ((fsize == k16BitSize) ? MOP_xuxth32 : MOP_xuxtw64))
5435                          : ((fsize == k8BitSize) ? MOP_xuxtb32 : MOP_xuxth32));
5436             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resOpnd, LoadIntoRegister(*opnd0, fromType)));
5437         }
5438     } else { /* Same size or truncate */
5439 #ifdef CNV_OPTIMIZE
5440         /*
5441          * No code needed for aarch64 with same reg.
5442          * Just update regno.
5443          */
5444         RegOperand *reg = static_cast<RegOperand *>(resOpnd);
5445         reg->regNo = static_cast<RegOperand *>(opnd0)->regNo;
5446 #else
5447         /*
5448          *  This is not really needed if opnd0 is result from a load.
5449          * Hopefully the FE will get rid of the redundant conversions for loads.
5450          */
5451         PrimType primType = ((fsize == k64BitSize) ? (IsSignedInteger(fromType) ? PTY_i64 : PTY_u64)
5452                                                    : (IsSignedInteger(fromType) ? PTY_i32 : PTY_u32));
5453         opnd0 = &LoadIntoRegister(*opnd0, primType);
5454 
5455         if (fsize > tsize) {
5456             if (tsize == k8BitSize) {
5457                 MOperator mOp = IsSignedInteger(toType) ? MOP_xsxtb32 : MOP_xuxtb32;
5458                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resOpnd, *opnd0));
5459             } else if (tsize == k16BitSize) {
5460                 MOperator mOp = IsSignedInteger(toType) ? MOP_xsxth32 : MOP_xuxth32;
5461                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resOpnd, *opnd0));
5462             } else {
5463                 MOperator mOp = IsSignedInteger(toType) ? MOP_xsbfxrri6i6 : MOP_xubfxrri6i6;
5464                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resOpnd, *opnd0,
5465                                                                    CreateImmOperand(0, k8BitSize, false),
5466                                                                    CreateImmOperand(tsize, k8BitSize, false)));
5467             }
5468         } else {
5469             /* same size, so resOpnd can be set */
5470             if ((IsSignedInteger(fromType) == IsSignedInteger(toType)) ||
5471                 (GetPrimTypeSize(toType) >= k4BitSize)) {
5472                 resOpnd = opnd0;
5473             } else if (IsUnsignedInteger(toType)) {
5474                 MOperator mop;
5475                 switch (toType) {
5476                     case PTY_u8:
5477                         mop = MOP_xuxtb32;
5478                         break;
5479                     case PTY_u16:
5480                         mop = MOP_xuxth32;
5481                         break;
5482                     default:
5483                         CHECK_FATAL(0, "Unhandled unsigned convert");
5484                 }
5485                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, *resOpnd, *opnd0));
5486             } else {
5487                 /* signed target */
5488                 uint32 size = GetPrimTypeSize(toType);
5489                 MOperator mop;
5490                 switch (toType) {
5491                     case PTY_i8:
5492                         mop = (size > k4BitSize) ? MOP_xsxtb64 : MOP_xsxtb32;
5493                         break;
5494                     case PTY_i16:
5495                         mop = (size > k4BitSize) ? MOP_xsxth64 : MOP_xsxth32;
5496                         break;
5497                     default:
5498                         CHECK_FATAL(0, "Unhandled unsigned convert");
5499                 }
5500                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, *resOpnd, *opnd0));
5501             }
5502         }
5503 #endif
5504     }
5505 }
5506 
SelectCvt(const BaseNode & parent,TypeCvtNode & node,Operand & opnd0)5507 Operand *AArch64CGFunc::SelectCvt(const BaseNode &parent, TypeCvtNode &node, Operand &opnd0)
5508 {
5509     PrimType fromType = node.FromType();
5510     PrimType toType = node.GetPrimType();
5511     if (fromType == toType) {
5512         return &opnd0; /* noop */
5513     }
5514     Operand *resOpnd = &GetOrCreateResOperand(parent, toType);
5515     if (IsPrimitiveFloat(toType) && IsPrimitiveInteger(fromType)) {
5516         SelectCvtInt2Float(*resOpnd, opnd0, toType, fromType);
5517     } else if (IsPrimitiveFloat(fromType) && IsPrimitiveInteger(toType)) {
5518         SelectCvtFloat2Int(*resOpnd, opnd0, toType, fromType);
5519     } else if (IsPrimitiveInteger(fromType) && IsPrimitiveInteger(toType)) {
5520         SelectCvtInt2Int(&parent, resOpnd, &opnd0, fromType, toType);
5521     } else if (IsPrimitiveVector(toType) || IsPrimitiveVector(fromType)) {
5522         CHECK_FATAL(IsPrimitiveVector(toType) && IsPrimitiveVector(fromType), "Invalid vector cvt operands");
5523         SelectVectorCvt(resOpnd, toType, &opnd0, fromType);
5524     } else { /* both are float type */
5525         SelectCvtFloat2Float(*resOpnd, opnd0, fromType, toType);
5526     }
5527     return resOpnd;
5528 }
5529 
SelectTrunc(TypeCvtNode & node,Operand & opnd0,const BaseNode & parent)5530 Operand *AArch64CGFunc::SelectTrunc(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent)
5531 {
5532     PrimType ftype = node.FromType();
5533     PrimType nodeType = node.GetPrimType();
5534     bool is64Bits = (GetPrimTypeBitSize(node.GetPrimType()) == k64BitSize);
5535     bool isFloat = (IsPrimitiveFloat(nodeType));
5536     if (isFloat) {
5537         CHECK_FATAL(nodeType == PTY_f32 || nodeType == PTY_f64, "only support f32, f64");
5538         return SelectRoundOperator(kTrunc, node, opnd0, parent);
5539     }
5540     PrimType itype = (is64Bits) ? (IsSignedInteger(node.GetPrimType()) ? PTY_i64 : PTY_u64)
5541                                 : (IsSignedInteger(node.GetPrimType()) ? PTY_i32 : PTY_u32); /* promoted type */
5542     RegOperand &resOpnd = GetOrCreateResOperand(parent, itype);
5543     SelectCvtFloat2Int(resOpnd, opnd0, itype, ftype);
5544     return &resOpnd;
5545 }
5546 
SelectSelect(Operand & resOpnd,Operand & condOpnd,Operand & trueOpnd,Operand & falseOpnd,PrimType dtype,PrimType ctype,bool hasCompare,ConditionCode cc)5547 void AArch64CGFunc::SelectSelect(Operand &resOpnd, Operand &condOpnd, Operand &trueOpnd, Operand &falseOpnd,
5548                                  PrimType dtype, PrimType ctype, bool hasCompare, ConditionCode cc)
5549 {
5550     DEBUG_ASSERT(&resOpnd != &condOpnd, "resOpnd cannot be the same as condOpnd");
5551     bool isIntType = IsPrimitiveInteger(dtype);
5552     DEBUG_ASSERT((IsPrimitiveInteger(dtype) || IsPrimitiveFloat(dtype)), "unknown type for select");
5553     // making condOpnd and cmpInsn closer will provide more opportunity for opt
5554     Operand &newTrueOpnd = LoadIntoRegister(trueOpnd, dtype);
5555     Operand &newFalseOpnd = LoadIntoRegister(falseOpnd, dtype);
5556     Operand &newCondOpnd = LoadIntoRegister(condOpnd, ctype);
5557     if (hasCompare) {
5558         SelectAArch64Cmp(newCondOpnd, CreateImmOperand(0, ctype, false), true, GetPrimTypeBitSize(ctype));
5559         cc = CC_NE;
5560     }
5561     Operand &newResOpnd = LoadIntoRegister(resOpnd, dtype);
5562     SelectAArch64Select(newResOpnd, newTrueOpnd, newFalseOpnd, GetCondOperand(cc), isIntType,
5563                         GetPrimTypeBitSize(dtype));
5564 }
5565 
SelectSelect(TernaryNode & expr,Operand & cond,Operand & trueOpnd,Operand & falseOpnd,const BaseNode & parent,bool hasCompare)5566 Operand *AArch64CGFunc::SelectSelect(TernaryNode &expr, Operand &cond, Operand &trueOpnd, Operand &falseOpnd,
5567                                      const BaseNode &parent, bool hasCompare)
5568 {
5569     PrimType dtype = expr.GetPrimType();
5570     PrimType ctype = expr.Opnd(0)->GetPrimType();
5571 
5572     ConditionCode cc = CC_NE;
5573     Opcode opcode = expr.Opnd(0)->GetOpCode();
5574     PrimType cmpType = static_cast<CompareNode *>(expr.Opnd(0))->GetOpndType();
5575     bool isFloat = false;
5576     bool unsignedIntegerComparison = false;
5577     if (!IsPrimitiveVector(cmpType)) {
5578         isFloat = IsPrimitiveFloat(cmpType);
5579         unsignedIntegerComparison = !isFloat && !IsSignedInteger(cmpType);
5580     } else {
5581         isFloat = IsPrimitiveVectorFloat(cmpType);
5582         unsignedIntegerComparison = !isFloat && IsPrimitiveUnSignedVector(cmpType);
5583     }
5584     switch (opcode) {
5585         case OP_eq:
5586             cc = CC_EQ;
5587             break;
5588         case OP_ne:
5589             cc = CC_NE;
5590             break;
5591         case OP_le:
5592             cc = unsignedIntegerComparison ? CC_LS : CC_LE;
5593             break;
5594         case OP_ge:
5595             cc = unsignedIntegerComparison ? CC_HS : CC_GE;
5596             break;
5597         case OP_gt:
5598             cc = unsignedIntegerComparison ? CC_HI : CC_GT;
5599             break;
5600         case OP_lt:
5601             cc = unsignedIntegerComparison ? CC_LO : CC_LT;
5602             break;
5603         default:
5604             hasCompare = true;
5605             break;
5606     }
5607     if (!IsPrimitiveVector(dtype)) {
5608         RegOperand &resOpnd = GetOrCreateResOperand(parent, dtype);
5609         SelectSelect(resOpnd, cond, trueOpnd, falseOpnd, dtype, ctype, hasCompare, cc);
5610         return &resOpnd;
5611     } else {
5612         return SelectVectorSelect(cond, dtype, trueOpnd, falseOpnd);
5613     }
5614 }
5615 
5616 /*
5617  * syntax: select <prim-type> (<opnd0>, <opnd1>, <opnd2>)
5618  * <opnd0> must be of integer type.
5619  * <opnd1> and <opnd2> must be of the type given by <prim-type>.
5620  * If <opnd0> is not 0, return <opnd1>.  Otherwise, return <opnd2>.
5621  */
SelectAArch64Select(Operand & dest,Operand & o0,Operand & o1,CondOperand & cond,bool isIntType,uint32 dsize)5622 void AArch64CGFunc::SelectAArch64Select(Operand &dest, Operand &o0, Operand &o1, CondOperand &cond, bool isIntType,
5623                                         uint32 dsize)
5624 {
5625     uint32 mOpCode =
5626         isIntType ? ((dsize == k64BitSize) ? MOP_xcselrrrc : MOP_wcselrrrc)
5627                   : ((dsize == k64BitSize) ? MOP_dcselrrrc : ((dsize == k32BitSize) ? MOP_scselrrrc : MOP_hcselrrrc));
5628     Operand &rflag = GetOrCreateRflag();
5629     if (o1.IsImmediate()) {
5630         uint32 movOp = (dsize == k64BitSize ? MOP_xmovri64 : MOP_wmovri32);
5631         RegOperand &movDest =
5632             CreateVirtualRegisterOperand(NewVReg(kRegTyInt, (dsize == k64BitSize) ? k8ByteSize : k4ByteSize));
5633         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(movOp, movDest, o1));
5634         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, dest, o0, movDest, cond, rflag));
5635         return;
5636     }
5637     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOpCode, dest, o0, o1, cond, rflag));
5638 }
5639 
SelectRangeGoto(RangeGotoNode & rangeGotoNode,Operand & srcOpnd)5640 void AArch64CGFunc::SelectRangeGoto(RangeGotoNode &rangeGotoNode, Operand &srcOpnd)
5641 {
5642     const SmallCaseVector &switchTable = rangeGotoNode.GetRangeGotoTable();
5643     MIRType *etype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast<TyIdx>(PTY_a64));
5644     /*
5645      * we store 8-byte displacement ( jump_label - offset_table_address )
5646      * in the table. Refer to AArch64Emit::Emit() in aarch64emit.cpp
5647      */
5648     std::vector<uint64> sizeArray;
5649     sizeArray.emplace_back(switchTable.size());
5650     MIRArrayType *arrayType = memPool->New<MIRArrayType>(etype->GetTypeIndex(), sizeArray);
5651     MIRAggConst *arrayConst = memPool->New<MIRAggConst>(mirModule, *arrayType);
5652     for (const auto &itPair : switchTable) {
5653         LabelIdx labelIdx = itPair.second;
5654         GetCurBB()->PushBackRangeGotoLabel(labelIdx);
5655         MIRConst *mirConst = memPool->New<MIRLblConst>(labelIdx, GetFunction().GetPuidx(), *etype);
5656         arrayConst->AddItem(mirConst, 0);
5657     }
5658 
5659     MIRSymbol *lblSt = GetFunction().GetSymTab()->CreateSymbol(kScopeLocal);
5660     lblSt->SetStorageClass(kScFstatic);
5661     lblSt->SetSKind(kStConst);
5662     lblSt->SetTyIdx(arrayType->GetTypeIndex());
5663     lblSt->SetKonst(arrayConst);
5664     std::string lblStr(".LB_");
5665     MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(GetFunction().GetStIdx().Idx());
5666     CHECK_FATAL(funcSt != nullptr, "funcSt should not be nullptr");
5667     uint32 labelIdxTmp = GetLabelIdx();
5668     lblStr += funcSt->GetName();
5669     lblStr += std::to_string(labelIdxTmp++);
5670     SetLabelIdx(labelIdxTmp);
5671     lblSt->SetNameStrIdx(lblStr);
5672     AddEmitSt(GetCurBB()->GetId(), *lblSt);
5673 
5674     PrimType itype = rangeGotoNode.Opnd(0)->GetPrimType();
5675     Operand &opnd0 = LoadIntoRegister(srcOpnd, itype);
5676 
5677     regno_t vRegNO = NewVReg(kRegTyInt, 8u);
5678     RegOperand *addOpnd = &CreateVirtualRegisterOperand(vRegNO);
5679 
5680     int32 minIdx = switchTable[0].first;
5681     SelectAdd(*addOpnd, opnd0,
5682               CreateImmOperand(-static_cast<int64>(minIdx) - static_cast<int64>(rangeGotoNode.GetTagOffset()),
5683                                GetPrimTypeBitSize(itype), true),
5684               itype);
5685 
5686     /* contains the index */
5687     if (addOpnd->GetSize() != GetPrimTypeBitSize(PTY_u64)) {
5688         addOpnd = static_cast<RegOperand *>(&SelectCopy(*addOpnd, PTY_u64, PTY_u64));
5689     }
5690 
5691     RegOperand &baseOpnd = CreateRegisterOperandOfType(PTY_u64);
5692     StImmOperand &stOpnd = CreateStImmOperand(*lblSt, 0, 0);
5693 
5694     /* load the address of the switch table */
5695     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, baseOpnd, stOpnd));
5696     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, baseOpnd, baseOpnd, stOpnd));
5697 
5698     /* load the displacement into a register by accessing memory at base + index*8 */
5699     Operand *disp = CreateMemOperand(MemOperand::kAddrModeBOrX, k64BitSize, baseOpnd, *addOpnd, k8BitShift);
5700     RegOperand &tgt = CreateRegisterOperandOfType(PTY_a64);
5701     SelectAdd(tgt, baseOpnd, *disp, PTY_u64);
5702     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xbr, tgt));
5703 }
5704 
SelectLazyLoad(Operand & opnd0,PrimType primType)5705 Operand *AArch64CGFunc::SelectLazyLoad(Operand &opnd0, PrimType primType)
5706 {
5707     DEBUG_ASSERT(opnd0.IsRegister(), "wrong type.");
5708     RegOperand &resOpnd = CreateRegisterOperandOfType(primType);
5709     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_lazy_ldr, resOpnd, opnd0));
5710     return &resOpnd;
5711 }
5712 
SelectLazyLoadStatic(MIRSymbol & st,int64 offset,PrimType primType)5713 Operand *AArch64CGFunc::SelectLazyLoadStatic(MIRSymbol &st, int64 offset, PrimType primType)
5714 {
5715     StImmOperand &srcOpnd = CreateStImmOperand(st, offset, 0);
5716     RegOperand &resOpnd = CreateRegisterOperandOfType(primType);
5717     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_lazy_ldr_static, resOpnd, srcOpnd));
5718     return &resOpnd;
5719 }
5720 
SelectLoadArrayClassCache(MIRSymbol & st,int64 offset,PrimType primType)5721 Operand *AArch64CGFunc::SelectLoadArrayClassCache(MIRSymbol &st, int64 offset, PrimType primType)
5722 {
5723     StImmOperand &srcOpnd = CreateStImmOperand(st, offset, 0);
5724     RegOperand &resOpnd = CreateRegisterOperandOfType(primType);
5725     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_arrayclass_cache_ldr, resOpnd, srcOpnd));
5726     return &resOpnd;
5727 }
5728 
SelectAlloca(UnaryNode & node,Operand & opnd0)5729 Operand *AArch64CGFunc::SelectAlloca(UnaryNode &node, Operand &opnd0)
5730 {
5731     if (!CGOptions::IsArm64ilp32()) {
5732         DEBUG_ASSERT((node.GetPrimType() == PTY_a64), "wrong type");
5733     }
5734     if (GetCG()->IsLmbc()) {
5735         SetHasVLAOrAlloca(true);
5736     }
5737     PrimType stype = node.Opnd(0)->GetPrimType();
5738     Operand *resOpnd = &opnd0;
5739     if (GetPrimTypeBitSize(stype) < GetPrimTypeBitSize(PTY_u64)) {
5740         resOpnd = &CreateRegisterOperandOfType(PTY_u64);
5741         SelectCvtInt2Int(nullptr, resOpnd, &opnd0, stype, PTY_u64);
5742     }
5743 
5744     RegOperand &aliOp = CreateRegisterOperandOfType(PTY_u64);
5745 
5746     SelectAdd(aliOp, *resOpnd, CreateImmOperand(kAarch64StackPtrAlignment - 1, k64BitSize, true), PTY_u64);
5747     Operand &shifOpnd = CreateImmOperand(__builtin_ctz(kAarch64StackPtrAlignment), k64BitSize, true);
5748     SelectShift(aliOp, aliOp, shifOpnd, kShiftLright, PTY_u64);
5749     SelectShift(aliOp, aliOp, shifOpnd, kShiftLeft, PTY_u64);
5750     Operand &spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt);
5751     SelectSub(spOpnd, spOpnd, aliOp, PTY_u64);
5752     int64 allocaOffset = GetMemlayout()->SizeOfArgsToStackPass();
5753     if (GetCG()->IsLmbc()) {
5754         allocaOffset -= kDivide2 * k8ByteSize;
5755     }
5756     if (allocaOffset > 0) {
5757         RegOperand &resallo = CreateRegisterOperandOfType(PTY_u64);
5758         SelectAdd(resallo, spOpnd, CreateImmOperand(allocaOffset, k64BitSize, true), PTY_u64);
5759         return &resallo;
5760     } else {
5761         return &SelectCopy(spOpnd, PTY_u64, PTY_u64);
5762     }
5763 }
5764 
SelectMalloc(UnaryNode & node,Operand & opnd0)5765 Operand *AArch64CGFunc::SelectMalloc(UnaryNode &node, Operand &opnd0)
5766 {
5767     PrimType retType = node.GetPrimType();
5768     DEBUG_ASSERT((retType == PTY_a64), "wrong type");
5769 
5770     std::vector<Operand *> opndVec;
5771     RegOperand &resOpnd = CreateRegisterOperandOfType(retType);
5772     opndVec.emplace_back(&resOpnd);
5773     opndVec.emplace_back(&opnd0);
5774     /* Use calloc to make sure allocated memory is zero-initialized */
5775     const std::string &funcName = "calloc";
5776     PrimType srcPty = PTY_u64;
5777     if (opnd0.GetSize() <= k32BitSize) {
5778         srcPty = PTY_u32;
5779     }
5780     Operand &opnd1 = CreateImmOperand(1, srcPty, false);
5781     opndVec.emplace_back(&opnd1);
5782     SelectLibCall(funcName, opndVec, srcPty, retType);
5783     return &resOpnd;
5784 }
5785 
SelectGCMalloc(GCMallocNode & node)5786 Operand *AArch64CGFunc::SelectGCMalloc(GCMallocNode &node)
5787 {
5788     PrimType retType = node.GetPrimType();
5789     DEBUG_ASSERT((retType == PTY_a64), "wrong type");
5790 
5791     /* Get the size and alignment of the type. */
5792     TyIdx tyIdx = node.GetTyIdx();
5793     uint64 size = GetBecommon().GetTypeSize(tyIdx);
5794     uint8 align = RTSupport::GetRTSupportInstance().GetObjectAlignment();
5795 
5796     /* Generate the call to MCC_NewObj */
5797     Operand &opndSize = CreateImmOperand(static_cast<int64>(size), k64BitSize, false);
5798     Operand &opndAlign = CreateImmOperand(align, k64BitSize, false);
5799 
5800     RegOperand &resOpnd = CreateRegisterOperandOfType(retType);
5801 
5802     std::vector<Operand *> opndVec {&resOpnd, &opndSize, &opndAlign};
5803 
5804     const std::string &funcName = "MCC_NewObj";
5805     SelectLibCall(funcName, opndVec, PTY_u64, retType);
5806 
5807     return &resOpnd;
5808 }
5809 
SelectJarrayMalloc(JarrayMallocNode & node,Operand & opnd0)5810 Operand *AArch64CGFunc::SelectJarrayMalloc(JarrayMallocNode &node, Operand &opnd0)
5811 {
5812     PrimType retType = node.GetPrimType();
5813     DEBUG_ASSERT((retType == PTY_a64), "wrong type");
5814 
5815     /* Extract jarray type */
5816     TyIdx tyIdx = node.GetTyIdx();
5817     MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
5818     DEBUG_ASSERT(type != nullptr, "nullptr check");
5819     CHECK_FATAL(type->GetKind() == kTypeJArray, "expect MIRJarrayType");
5820     auto jaryType = static_cast<MIRJarrayType *>(type);
5821     uint64 fixedSize = RTSupport::GetRTSupportInstance().GetArrayContentOffset();
5822     uint8 align = RTSupport::GetRTSupportInstance().GetObjectAlignment();
5823 
5824     MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(jaryType->GetElemTyIdx());
5825     PrimType elemPrimType = elemType->GetPrimType();
5826     uint64 elemSize = GetPrimTypeSize(elemPrimType);
5827 
5828     /* Generate the cal to MCC_NewObj_flexible */
5829     Operand &opndFixedSize = CreateImmOperand(PTY_u64, static_cast<int64>(fixedSize));
5830     Operand &opndElemSize = CreateImmOperand(PTY_u64, static_cast<int64>(elemSize));
5831 
5832     Operand *opndNElems = &opnd0;
5833 
5834     Operand *opndNElems64 = &static_cast<Operand &>(CreateRegisterOperandOfType(PTY_u64));
5835     SelectCvtInt2Int(nullptr, opndNElems64, opndNElems, PTY_u32, PTY_u64);
5836 
5837     Operand &opndAlign = CreateImmOperand(PTY_u64, align);
5838 
5839     RegOperand &resOpnd = CreateRegisterOperandOfType(retType);
5840 
5841     std::vector<Operand *> opndVec {&resOpnd, &opndFixedSize, &opndElemSize, opndNElems64, &opndAlign};
5842 
5843     const std::string &funcName = "MCC_NewObj_flexible";
5844     SelectLibCall(funcName, opndVec, PTY_u64, retType);
5845 
5846     /* Generate the store of the object length field */
5847     MemOperand &opndArrayLengthField =
5848         CreateMemOpnd(resOpnd, static_cast<int64>(RTSupport::GetRTSupportInstance().GetArrayLengthOffset()), k4BitSize);
5849     RegOperand *regOpndNElems = &SelectCopy(*opndNElems, PTY_u32, PTY_u32);
5850     DEBUG_ASSERT(regOpndNElems != nullptr, "null ptr check!");
5851     SelectCopy(opndArrayLengthField, PTY_u32, *regOpndNElems, PTY_u32);
5852 
5853     return &resOpnd;
5854 }
5855 
IsRegRematCand(const RegOperand & reg) const5856 bool AArch64CGFunc::IsRegRematCand(const RegOperand &reg) const
5857 {
5858     MIRPreg *preg = GetPseudoRegFromVirtualRegNO(reg.GetRegisterNumber(), CGOptions::DoCGSSA());
5859     if (preg != nullptr && preg->GetOp() != OP_undef) {
5860         if (preg->GetOp() == OP_constval && cg->GetRematLevel() >= kRematConst) {
5861             return true;
5862         } else if (preg->GetOp() == OP_addrof && cg->GetRematLevel() >= kRematAddr) {
5863             return true;
5864         } else if (preg->GetOp() == OP_iread && cg->GetRematLevel() >= kRematDreadGlobal) {
5865             return true;
5866         } else {
5867             return false;
5868         }
5869     } else {
5870         return false;
5871     }
5872 }
5873 
ClearRegRematInfo(const RegOperand & reg) const5874 void AArch64CGFunc::ClearRegRematInfo(const RegOperand &reg) const
5875 {
5876     MIRPreg *preg = GetPseudoRegFromVirtualRegNO(reg.GetRegisterNumber(), CGOptions::DoCGSSA());
5877     if (preg != nullptr && preg->GetOp() != OP_undef) {
5878         preg->SetOp(OP_undef);
5879     }
5880 }
5881 
IsRegSameRematInfo(const RegOperand & regDest,const RegOperand & regSrc) const5882 bool AArch64CGFunc::IsRegSameRematInfo(const RegOperand &regDest, const RegOperand &regSrc) const
5883 {
5884     MIRPreg *pregDest = GetPseudoRegFromVirtualRegNO(regDest.GetRegisterNumber(), CGOptions::DoCGSSA());
5885     MIRPreg *pregSrc = GetPseudoRegFromVirtualRegNO(regSrc.GetRegisterNumber(), CGOptions::DoCGSSA());
5886     if (pregDest != nullptr && pregDest == pregSrc) {
5887         if (pregDest->GetOp() == OP_constval && cg->GetRematLevel() >= kRematConst) {
5888             return true;
5889         } else if (pregDest->GetOp() == OP_addrof && cg->GetRematLevel() >= kRematAddr) {
5890             return true;
5891         } else if (pregDest->GetOp() == OP_iread && cg->GetRematLevel() >= kRematDreadGlobal) {
5892             return true;
5893         } else {
5894             return false;
5895         }
5896     } else {
5897         return false;
5898     }
5899 }
5900 
ReplaceOpndInInsn(RegOperand & regDest,RegOperand & regSrc,Insn & insn,regno_t destNO)5901 void AArch64CGFunc::ReplaceOpndInInsn(RegOperand &regDest, RegOperand &regSrc, Insn &insn, regno_t destNO)
5902 {
5903     auto opndNum = static_cast<int32>(insn.GetOperandSize());
5904     for (int i = opndNum - 1; i >= 0; --i) {
5905         Operand &opnd = insn.GetOperand(static_cast<uint32>(i));
5906         if (opnd.IsList()) {
5907             std::list<RegOperand *> tempRegStore;
5908             auto &opndList = static_cast<ListOperand &>(opnd).GetOperands();
5909             bool needReplace = false;
5910             for (auto it = opndList.cbegin(), end = opndList.cend(); it != end; ++it) {
5911                 auto *regOpnd = *it;
5912                 if (regOpnd->GetRegisterNumber() == destNO) {
5913                     needReplace = true;
5914                     tempRegStore.push_back(&regSrc);
5915                 } else {
5916                     tempRegStore.push_back(regOpnd);
5917                 }
5918             }
5919             if (needReplace) {
5920                 opndList.clear();
5921                 for (auto &newOpnd : std::as_const(tempRegStore)) {
5922                     static_cast<ListOperand &>(opnd).PushOpnd(*newOpnd);
5923                 }
5924             }
5925         } else if (opnd.IsMemoryAccessOperand()) {
5926             auto &memOpnd = static_cast<MemOperand &>(opnd);
5927             RegOperand *baseRegOpnd = memOpnd.GetBaseRegister();
5928             RegOperand *indexRegOpnd = memOpnd.GetIndexRegister();
5929             MemOperand *newMem = static_cast<MemOperand *>(memOpnd.Clone(*GetMemoryPool()));
5930             if ((baseRegOpnd != nullptr && baseRegOpnd->GetRegisterNumber() == destNO) ||
5931                 (indexRegOpnd != nullptr && indexRegOpnd->GetRegisterNumber() == destNO)) {
5932                 if (baseRegOpnd != nullptr && baseRegOpnd->GetRegisterNumber() == destNO) {
5933                     newMem->SetBaseRegister(regSrc);
5934                 }
5935                 if (indexRegOpnd != nullptr && indexRegOpnd->GetRegisterNumber() == destNO) {
5936                     auto *newRegSrc = static_cast<RegOperand *>(regSrc.Clone(*GetMemoryPool()));
5937                     newRegSrc->SetSize(indexRegOpnd->GetSize());  // retain the original size
5938                     newMem->SetIndexRegister(*newRegSrc);
5939                 }
5940                 insn.SetMemOpnd(newMem);
5941             }
5942         } else if (opnd.IsRegister()) {
5943             auto &regOpnd = static_cast<RegOperand &>(opnd);
5944             if (regOpnd.GetRegisterNumber() == destNO) {
5945                 DEBUG_ASSERT(regOpnd.GetRegisterNumber() != kRFLAG, "both condi and reg");
5946                 if (regOpnd.GetBaseRefOpnd() != nullptr) {
5947                     regSrc.SetBaseRefOpnd(*regOpnd.GetBaseRefOpnd());
5948                     ReplaceRegReference(regOpnd.GetRegisterNumber(), regSrc.GetRegisterNumber());
5949                 }
5950                 CHECK_FATAL(regOpnd.GetSize() == regSrc.GetSize(), "NIY");
5951                 insn.SetOperand(static_cast<uint32>(i), regSrc);
5952             }
5953             if (!IsStackMapComputed() && regOpnd.GetBaseRefOpnd() != nullptr &&
5954                 regOpnd.GetBaseRefOpnd()->GetRegisterNumber() == destNO) {
5955                 regOpnd.SetBaseRefOpnd(regSrc);
5956                 ReplaceRegReference(regOpnd.GetBaseRefOpnd()->GetRegisterNumber(), regSrc.GetRegisterNumber());
5957             }
5958         }
5959     }
5960     if (!IsStackMapComputed() && insn.GetStackMap() != nullptr) {
5961         for (auto [deoptVreg, opnd] : insn.GetStackMap()->GetDeoptInfo().GetDeoptBundleInfo()) {
5962             if (!opnd->IsRegister()) {
5963                 continue;
5964             }
5965             auto &regOpnd = static_cast<RegOperand &>(*opnd);
5966             if (regOpnd.GetRegisterNumber() == destNO) {
5967                 insn.GetStackMap()->GetDeoptInfo().ReplaceDeoptBundleInfo(deoptVreg, regSrc);
5968                 ReplaceRegReference(regOpnd.GetRegisterNumber(), regSrc.GetRegisterNumber());
5969             }
5970         }
5971     }
5972 }
5973 
CleanupDeadMov(bool dumpInfo)5974 void AArch64CGFunc::CleanupDeadMov(bool dumpInfo)
5975 {
5976     /* clean dead mov. */
5977     FOR_ALL_BB(bb, this)
5978     {
5979         FOR_BB_INSNS_SAFE(insn, bb, ninsn)
5980         {
5981             if (!insn->IsMachineInstruction()) {
5982                 continue;
5983             }
5984             if (insn->GetMachineOpcode() == MOP_xmovrr || insn->GetMachineOpcode() == MOP_wmovrr ||
5985                 insn->GetMachineOpcode() == MOP_xvmovs || insn->GetMachineOpcode() == MOP_xvmovd) {
5986                 RegOperand &regDest = static_cast<RegOperand &>(insn->GetOperand(kInsnFirstOpnd));
5987                 RegOperand &regSrc = static_cast<RegOperand &>(insn->GetOperand(kInsnSecondOpnd));
5988                 if (!regSrc.IsVirtualRegister() || !regDest.IsVirtualRegister()) {
5989                     continue;
5990                 }
5991 
5992                 if (regSrc.GetRegisterNumber() == regDest.GetRegisterNumber()) {
5993                     bb->RemoveInsn(*insn);
5994                 } else if (insn->IsPhiMovInsn() && dumpInfo) {
5995                     LogInfo::MapleLogger() << "fail to remove mov: " << regDest.GetRegisterNumber() << " <- "
5996                                            << regSrc.GetRegisterNumber() << std::endl;
5997                 }
5998             }
5999         }
6000     }
6001 }
6002 
GetRealCallerSaveRegs(const Insn & insn,std::set<regno_t> & realSaveRegs)6003 void AArch64CGFunc::GetRealCallerSaveRegs(const Insn &insn, std::set<regno_t> &realSaveRegs)
6004 {
6005     auto *targetOpnd = insn.GetCallTargetOperand();
6006     CHECK_FATAL(targetOpnd != nullptr, "target is null in AArch64Insn::IsCallToFunctionThatNeverReturns");
6007     if (CGOptions::DoIPARA() && targetOpnd->IsFuncNameOpnd()) {
6008         FuncNameOperand *target = static_cast<FuncNameOperand *>(targetOpnd);
6009         const MIRSymbol *funcSt = target->GetFunctionSymbol();
6010         DEBUG_ASSERT(funcSt->GetSKind() == kStFunc, "funcst must be a function name symbol");
6011         MIRFunction *func = funcSt->GetFunction();
6012         if (func != nullptr && func->IsReferedRegsValid()) {
6013             for (auto preg : func->GetReferedRegs()) {
6014                 if (AArch64Abi::IsCallerSaveReg(static_cast<AArch64reg>(preg))) {
6015                     realSaveRegs.insert(preg);
6016                 }
6017             }
6018             return;
6019         }
6020     }
6021     for (uint32 i = R0; i <= kMaxRegNum; ++i) {
6022         if (AArch64Abi::IsCallerSaveReg(static_cast<AArch64reg>(i))) {
6023             realSaveRegs.insert(i);
6024         }
6025     }
6026 }
6027 
GetZeroOpnd(uint32 bitLen)6028 RegOperand &AArch64CGFunc::GetZeroOpnd(uint32 bitLen)
6029 {
6030     /*
6031      * It is possible to have a bitLen < 32, eg stb.
6032      * Set it to 32 if it is less than 32.
6033      */
6034     if (bitLen < k32BitSize) {
6035         bitLen = k32BitSize;
6036     }
6037     DEBUG_ASSERT((bitLen == k32BitSize || bitLen == k64BitSize), "illegal bit length = %d", bitLen);
6038     return (bitLen == k32BitSize) ? GetOrCreatePhysicalRegisterOperand(RZR, k32BitSize, kRegTyInt)
6039                                   : GetOrCreatePhysicalRegisterOperand(RZR, k64BitSize, kRegTyInt);
6040 }
6041 
IsFrameReg(const RegOperand & opnd) const6042 bool AArch64CGFunc::IsFrameReg(const RegOperand &opnd) const
6043 {
6044     if (opnd.GetRegisterNumber() == RFP) {
6045         return true;
6046     } else {
6047         return false;
6048     }
6049 }
6050 
IsSaveReg(const RegOperand & reg,MIRType & mirType,BECommon & cgBeCommon)6051 bool AArch64CGFunc::IsSaveReg(const RegOperand &reg, MIRType &mirType, BECommon &cgBeCommon)
6052 {
6053     CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind());
6054     CCLocInfo retMechanism;
6055     retLocator.LocateRetVal(mirType, retMechanism);
6056     if (retMechanism.GetRegCount() > 0) {
6057         return reg.GetRegisterNumber() == retMechanism.GetReg0() || reg.GetRegisterNumber() == retMechanism.GetReg1() ||
6058                reg.GetRegisterNumber() == retMechanism.GetReg2() || reg.GetRegisterNumber() == retMechanism.GetReg3();
6059     }
6060     return false;
6061 }
6062 
IsSPOrFP(const RegOperand & opnd) const6063 bool AArch64CGFunc::IsSPOrFP(const RegOperand &opnd) const
6064 {
6065     const RegOperand &regOpnd = static_cast<const RegOperand &>(opnd);
6066     regno_t regNO = opnd.GetRegisterNumber();
6067     return (regOpnd.IsPhysicalRegister() &&
6068             (regNO == RSP || regNO == RFP || (regNO == R29 && CGOptions::UseFramePointer())));
6069 }
6070 
IsReturnReg(const RegOperand & opnd) const6071 bool AArch64CGFunc::IsReturnReg(const RegOperand &opnd) const
6072 {
6073     regno_t regNO = opnd.GetRegisterNumber();
6074     return (regNO == R0) || (regNO == V0);
6075 }
6076 
6077 /*
6078  * This function returns true to indicate that the clean up code needs to be generated,
6079  * otherwise it does not need. In GCOnly mode, it always returns false.
6080  */
NeedCleanup()6081 bool AArch64CGFunc::NeedCleanup()
6082 {
6083     if (CGOptions::IsGCOnly()) {
6084         return false;
6085     }
6086     AArch64MemLayout *layout = static_cast<AArch64MemLayout *>(GetMemlayout());
6087     if (layout->GetSizeOfRefLocals() > 0) {
6088         return true;
6089     }
6090     for (uint32 i = 0; i < GetFunction().GetFormalCount(); i++) {
6091         TypeAttrs ta = GetFunction().GetNthParamAttr(i);
6092         if (ta.GetAttr(ATTR_localrefvar)) {
6093             return true;
6094         }
6095     }
6096 
6097     return false;
6098 }
6099 
6100 /*
6101  * bb must be the cleanup bb.
6102  * this function must be invoked before register allocation.
6103  * extended epilogue is specific for fast exception handling and is made up of
6104  * clean up code and epilogue.
6105  * clean up code is generated here while epilogue is generated in GeneratePrologEpilog()
6106  */
GenerateCleanupCodeForExtEpilog(BB & bb)6107 void AArch64CGFunc::GenerateCleanupCodeForExtEpilog(BB &bb)
6108 {
6109     DEBUG_ASSERT(GetLastBB()->GetPrev()->GetFirstStmt() == GetCleanupLabel(), "must be");
6110 
6111     if (NeedCleanup()) {
6112         /* this is necessary for code insertion. */
6113         SetCurBB(bb);
6114 
6115         RegOperand &regOpnd0 =
6116             GetOrCreatePhysicalRegisterOperand(R0, GetPointerSize() * kBitsPerByte, GetRegTyFromPrimTy(PTY_a64));
6117         RegOperand &regOpnd1 =
6118             GetOrCreatePhysicalRegisterOperand(R1, GetPointerSize() * kBitsPerByte, GetRegTyFromPrimTy(PTY_a64));
6119         /* allocate 16 bytes to store reg0 and reg1 (each reg has 8 bytes) */
6120         MemOperand &frameAlloc = CreateCallFrameOperand(-16, GetPointerSize() * kBitsPerByte);
6121         Insn &allocInsn = GetInsnBuilder()->BuildInsn(MOP_xstp, regOpnd0, regOpnd1, frameAlloc);
6122         allocInsn.SetDoNotRemove(true);
6123         AppendInstructionTo(allocInsn, *this);
6124 
6125         /* invoke MCC_CleanupLocalStackRef(). */
6126         HandleRCCall(false);
6127         /* deallocate 16 bytes which used to store reg0 and reg1 */
6128         MemOperand &frameDealloc = CreateCallFrameOperand(16, GetPointerSize() * kBitsPerByte);
6129         GenRetCleanup(cleanEANode, true);
6130         Insn &deallocInsn = GetInsnBuilder()->BuildInsn(MOP_xldp, regOpnd0, regOpnd1, frameDealloc);
6131         deallocInsn.SetDoNotRemove(true);
6132         AppendInstructionTo(deallocInsn, *this);
6133         /* Update cleanupbb since bb may have been splitted */
6134         SetCleanupBB(*GetCurBB());
6135     }
6136 }
6137 
6138 /*
6139  * bb must be the cleanup bb.
6140  * this function must be invoked before register allocation.
6141  */
GenerateCleanupCode(BB & bb)6142 void AArch64CGFunc::GenerateCleanupCode(BB &bb)
6143 {
6144     DEBUG_ASSERT(GetLastBB()->GetPrev()->GetFirstStmt() == GetCleanupLabel(), "must be");
6145     if (!NeedCleanup()) {
6146         return;
6147     }
6148 
6149     /* this is necessary for code insertion. */
6150     SetCurBB(bb);
6151 
6152     /* R0 is lived-in for clean-up code, save R0 before invocation */
6153     RegOperand &livein = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6154 
6155     if (!GetCG()->GenLocalRC()) {
6156         /* by pass local RC operations. */
6157     } else if (Globals::GetInstance()->GetOptimLevel() > CGOptions::kLevel0) {
6158         regno_t vreg = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
6159         RegOperand &backupRegOp = CreateVirtualRegisterOperand(vreg);
6160         backupRegOp.SetRegNotBBLocal();
6161         SelectCopy(backupRegOp, PTY_a64, livein, PTY_a64);
6162 
6163         /* invoke MCC_CleanupLocalStackRef(). */
6164         HandleRCCall(false);
6165         SelectCopy(livein, PTY_a64, backupRegOp, PTY_a64);
6166     } else {
6167         /*
6168          * Register Allocation for O0 can not handle this case, so use a callee saved register directly.
6169          * If yieldpoint is enabled, we use R20 instead R19.
6170          */
6171         AArch64reg backupRegNO = GetCG()->GenYieldPoint() ? R20 : R19;
6172         RegOperand &backupRegOp =
6173             GetOrCreatePhysicalRegisterOperand(backupRegNO, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6174         SelectCopy(backupRegOp, PTY_a64, livein, PTY_a64);
6175         /* invoke MCC_CleanupLocalStackRef(). */
6176         HandleRCCall(false);
6177         SelectCopy(livein, PTY_a64, backupRegOp, PTY_a64);
6178     }
6179 
6180     /* invoke _Unwind_Resume */
6181     std::string funcName("_Unwind_Resume");
6182     MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6183     sym->SetNameStrIdx(funcName);
6184     sym->SetStorageClass(kScText);
6185     sym->SetSKind(kStFunc);
6186     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6187     srcOpnds->PushOpnd(livein);
6188     AppendCall(*sym, *srcOpnds);
6189     /*
6190      * this instruction is unreachable, but we need it as the return address of previous
6191      * "bl _Unwind_Resume" for stack unwinding.
6192      */
6193     Insn &nop = GetInsnBuilder()->BuildInsn(MOP_xblr, livein, *srcOpnds);
6194     GetCurBB()->AppendInsn(nop);
6195     GetCurBB()->SetHasCall();
6196 
6197     /* Update cleanupbb since bb may have been splitted */
6198     SetCleanupBB(*GetCurBB());
6199 }
6200 
FloatParamRegRequired(MIRStructType * structType,uint32 & fpSize)6201 uint32 AArch64CGFunc::FloatParamRegRequired(MIRStructType *structType, uint32 &fpSize)
6202 {
6203     AArch64CallConvImpl parmlocator(GetBecommon());
6204     return parmlocator.FloatParamRegRequired(*structType, fpSize);
6205 }
6206 
6207 /*
6208  * Map param registers to formals.  For small structs passed in param registers,
6209  * create a move to vreg since lmbc IR does not create a regassign for them.
6210  */
AssignLmbcFormalParams()6211 void AArch64CGFunc::AssignLmbcFormalParams()
6212 {
6213     PrimType primType;
6214     uint32 offset;
6215     regno_t intReg = R0;
6216     regno_t fpReg = V0;
6217     for (auto param : GetLmbcParamVec()) {
6218         primType = param->GetPrimType();
6219         offset = param->GetOffset();
6220         if (param->IsReturn()) {
6221             param->SetRegNO(R8);
6222         } else if (IsPrimitiveInteger(primType)) {
6223             if (intReg > R7) {
6224                 param->SetRegNO(0);
6225             } else {
6226                 param->SetRegNO(intReg);
6227                 if (!param->HasRegassign()) {
6228                     uint32 bytelen = GetPrimTypeSize(primType);
6229                     uint32 bitlen = bytelen * kBitsPerByte;
6230                     MemOperand *mOpnd = GenLmbcFpMemOperand(static_cast<int32>(offset), bytelen);
6231                     RegOperand &src = GetOrCreatePhysicalRegisterOperand(AArch64reg(intReg), bitlen, kRegTyInt);
6232                     MOperator mOp = PickStInsn(bitlen, primType);
6233                     Insn &store = GetInsnBuilder()->BuildInsn(mOp, src, *mOpnd);
6234                     GetCurBB()->AppendInsn(store);
6235                 }
6236                 intReg++;
6237             }
6238         } else if (IsPrimitiveFloat(primType)) {
6239             if (fpReg > V7) {
6240                 param->SetRegNO(0);
6241             } else {
6242                 param->SetRegNO(fpReg);
6243                 if (!param->HasRegassign()) {
6244                     uint32 bytelen = GetPrimTypeSize(primType);
6245                     uint32 bitlen = bytelen * kBitsPerByte;
6246                     MemOperand *mOpnd = GenLmbcFpMemOperand(static_cast<int32>(offset), bytelen);
6247                     RegOperand &src = GetOrCreatePhysicalRegisterOperand(AArch64reg(fpReg), bitlen, kRegTyFloat);
6248                     MOperator mOp = PickStInsn(bitlen, primType);
6249                     Insn &store = GetInsnBuilder()->BuildInsn(mOp, src, *mOpnd);
6250                     GetCurBB()->AppendInsn(store);
6251                 }
6252                 fpReg++;
6253             }
6254         } else if (primType == PTY_agg) {
6255             if (param->IsPureFloat()) {
6256                 uint32 numFpRegs = param->GetNumRegs();
6257                 if ((fpReg + numFpRegs - kOneRegister) > V7) {
6258                     param->SetRegNO(0);
6259                 } else {
6260                     param->SetRegNO(fpReg);
6261                     param->SetNumRegs(numFpRegs);
6262                     fpReg += numFpRegs;
6263                 }
6264             } else if (param->GetSize() > k16ByteSize) {
6265                 if (intReg > R7) {
6266                     param->SetRegNO(0);
6267                 } else {
6268                     param->SetRegNO(intReg);
6269                     param->SetIsOnStack();
6270                     param->SetOnStackOffset(((intReg - R0 + fpReg) - V0) * k8ByteSize);
6271                     uint32 bytelen = GetPrimTypeSize(PTY_a64);
6272                     uint32 bitlen = bytelen * kBitsPerByte;
6273                     MemOperand *mOpnd = GenLmbcFpMemOperand(static_cast<int32>(param->GetOnStackOffset()), bytelen);
6274                     RegOperand &src = GetOrCreatePhysicalRegisterOperand(AArch64reg(intReg), bitlen, kRegTyInt);
6275                     MOperator mOp = PickStInsn(bitlen, PTY_a64);
6276                     Insn &store = GetInsnBuilder()->BuildInsn(mOp, src, *mOpnd);
6277                     GetCurBB()->AppendInsn(store);
6278                     intReg++;
6279                 }
6280             } else if (param->GetSize() <= k8ByteSize) {
6281                 if (intReg > R7) {
6282                     param->SetRegNO(0);
6283                 } else {
6284                     param->SetRegNO(intReg);
6285                     param->SetNumRegs(kOneRegister);
6286                     intReg++;
6287                 }
6288             } else {
6289                 /* size > 8 && size <= 16 */
6290                 if ((intReg + kOneRegister) > R7) {
6291                     param->SetRegNO(0);
6292                 } else {
6293                     param->SetRegNO(intReg);
6294                     param->SetNumRegs(kTwoRegister);
6295                     intReg += kTwoRegister;
6296                 }
6297             }
6298             if (param->GetRegNO() != 0) {
6299                 for (uint32 i = 0; i < param->GetNumRegs(); ++i) {
6300                     PrimType pType = PTY_i64;
6301                     RegType rType = kRegTyInt;
6302                     uint32 rSize = k8ByteSize;
6303                     if (param->IsPureFloat()) {
6304                         rType = kRegTyFloat;
6305                         if (param->GetFpSize() <= k4ByteSize) {
6306                             pType = PTY_f32;
6307                             rSize = k4ByteSize;
6308                         } else {
6309                             pType = PTY_f64;
6310                         }
6311                     }
6312                     regno_t vreg = NewVReg(rType, rSize);
6313                     RegOperand &dest = GetOrCreateVirtualRegisterOperand(vreg);
6314                     RegOperand &src = GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(param->GetRegNO() + i),
6315                                                                          rSize * kBitsPerByte, rType);
6316                     SelectCopy(dest, pType, src, pType);
6317                     if (param->GetVregNO() == 0) {
6318                         param->SetVregNO(vreg);
6319                     }
6320                     Operand *memOpd = &CreateMemOpnd(RFP, offset + (i * rSize), rSize);
6321                     GetCurBB()->AppendInsn(
6322                         GetInsnBuilder()->BuildInsn(PickStInsn(rSize * kBitsPerByte, pType), dest, *memOpd));
6323                 }
6324             }
6325         } else {
6326             CHECK_FATAL(false, "lmbc formal primtype not handled");
6327         }
6328     }
6329 }
6330 
LmbcGenSaveSpForAlloca()6331 void AArch64CGFunc::LmbcGenSaveSpForAlloca()
6332 {
6333     if (GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc || !HasVLAOrAlloca()) {
6334         return;
6335     }
6336     Operand &spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt);
6337     regno_t regno = NewVReg(kRegTyInt, GetPointerSize());
6338     RegOperand &spSaveOpnd = CreateVirtualRegisterOperand(regno);
6339     SetSpSaveReg(regno);
6340     Insn &save = GetInsnBuilder()->BuildInsn(MOP_xmovrr, spSaveOpnd, spOpnd);
6341     GetFirstBB()->AppendInsn(save);
6342     for (auto *retBB : GetExitBBsVec()) {
6343         Insn &restore = GetInsnBuilder()->BuildInsn(MOP_xmovrr, spOpnd, spSaveOpnd);
6344         retBB->AppendInsn(restore);
6345         restore.SetFrameDef(true);
6346     }
6347 }
6348 
6349 /* if offset < 0, allocation; otherwise, deallocation */
CreateCallFrameOperand(int32 offset,uint32 size)6350 MemOperand &AArch64CGFunc::CreateCallFrameOperand(int32 offset, uint32 size)
6351 {
6352     MemOperand *memOpnd = CreateStackMemOpnd(RSP, offset, size);
6353     memOpnd->SetIndexOpt((offset < 0) ? MemOperand::kPreIndex : MemOperand::kPostIndex);
6354     return *memOpnd;
6355 }
6356 
GetLogicalShiftLeftOperand(uint32 shiftAmount,bool is64bits) const6357 BitShiftOperand *AArch64CGFunc::GetLogicalShiftLeftOperand(uint32 shiftAmount, bool is64bits) const
6358 {
6359     /* num(0, 16, 32, 48) >> 4 is num1(0, 1, 2, 3), num1 & (~3) == 0 */
6360     DEBUG_ASSERT((!shiftAmount || ((shiftAmount >> 4) & ~static_cast<uint32>(3)) == 0),
6361                  "shift amount should be one of 0, 16, 32, 48");
6362     /* movkLslOperands[4]~movkLslOperands[7] is for 64 bits */
6363     return &movkLslOperands[(shiftAmount >> 4) + (is64bits ? 4 : 0)];
6364 }
6365 
6366 AArch64CGFunc::MovkLslOperandArray AArch64CGFunc::movkLslOperands = {
6367     BitShiftOperand(BitShiftOperand::kLSL, 0, 4),
6368     BitShiftOperand(BitShiftOperand::kLSL, 16, 4),
6369     BitShiftOperand(BitShiftOperand::kLSL, static_cast<uint32>(-1), 0), /* invalid entry */
6370     BitShiftOperand(BitShiftOperand::kLSL, static_cast<uint32>(-1), 0), /* invalid entry */
6371     BitShiftOperand(BitShiftOperand::kLSL, 0, 6),
6372     BitShiftOperand(BitShiftOperand::kLSL, 16, 6),
6373     BitShiftOperand(BitShiftOperand::kLSL, 32, 6),
6374     BitShiftOperand(BitShiftOperand::kLSL, 48, 6),
6375 };
6376 
CreateStkTopOpnd(uint32 offset,uint32 size)6377 MemOperand &AArch64CGFunc::CreateStkTopOpnd(uint32 offset, uint32 size)
6378 {
6379     AArch64reg reg;
6380     if (GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) {
6381         reg = RSP;
6382     } else {
6383         reg = RFP;
6384     }
6385     MemOperand *memOp = CreateStackMemOpnd(reg, static_cast<int32>(offset), size);
6386     return *memOp;
6387 }
6388 
CreateStackMemOpnd(regno_t preg,int32 offset,uint32 size)6389 MemOperand *AArch64CGFunc::CreateStackMemOpnd(regno_t preg, int32 offset, uint32 size)
6390 {
6391     auto *memOp =
6392         memPool->New<MemOperand>(memPool->New<RegOperand>(preg, k64BitSize, kRegTyInt),
6393                                  &CreateOfstOpnd(static_cast<uint64>(static_cast<int64>(offset)), k32BitSize), size);
6394     if (preg == RFP || preg == RSP) {
6395         memOp->SetStackMem(true);
6396     }
6397     return memOp;
6398 }
6399 
6400 /* Mem mod BOI || PreIndex || PostIndex */
CreateMemOperand(uint32 size,RegOperand & base,ImmOperand & ofstOp,bool isVolatile,MemOperand::AArch64AddressingMode mode) const6401 MemOperand *AArch64CGFunc::CreateMemOperand(uint32 size, RegOperand &base, ImmOperand &ofstOp, bool isVolatile,
6402                                             MemOperand::AArch64AddressingMode mode) const
6403 {
6404     auto *memOp = memPool->New<MemOperand>(size, base, ofstOp, mode);
6405     memOp->SetVolatile(isVolatile);
6406     if (base.GetRegisterNumber() == RFP || base.GetRegisterNumber() == RSP) {
6407         memOp->SetStackMem(true);
6408     }
6409     return memOp;
6410 }
6411 
CreateMemOperand(MemOperand::AArch64AddressingMode mode,uint32 size,RegOperand & base,RegOperand * index,ImmOperand * offset,const MIRSymbol * symbol) const6412 MemOperand *AArch64CGFunc::CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base,
6413                                             RegOperand *index, ImmOperand *offset, const MIRSymbol *symbol) const
6414 {
6415     auto *memOp = memPool->New<MemOperand>(mode, size, base, index, offset, symbol);
6416     if (base.GetRegisterNumber() == RFP || base.GetRegisterNumber() == RSP) {
6417         memOp->SetStackMem(true);
6418     }
6419     return memOp;
6420 }
6421 
CreateMemOperand(MemOperand::AArch64AddressingMode mode,uint32 size,RegOperand & base,RegOperand & index,ImmOperand * offset,const MIRSymbol & symbol,bool noExtend)6422 MemOperand *AArch64CGFunc::CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base,
6423                                             RegOperand &index, ImmOperand *offset, const MIRSymbol &symbol,
6424                                             bool noExtend)
6425 {
6426     auto *memOp = memPool->New<MemOperand>(mode, size, base, index, offset, symbol, noExtend);
6427     if (base.GetRegisterNumber() == RFP || base.GetRegisterNumber() == RSP) {
6428         memOp->SetStackMem(true);
6429     }
6430     return memOp;
6431 }
6432 
CreateMemOperand(MemOperand::AArch64AddressingMode mode,uint32 dSize,RegOperand & base,RegOperand & indexOpnd,uint32 shift,bool isSigned) const6433 MemOperand *AArch64CGFunc::CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 dSize, RegOperand &base,
6434                                             RegOperand &indexOpnd, uint32 shift, bool isSigned) const
6435 {
6436     auto *memOp = memPool->New<MemOperand>(mode, dSize, base, indexOpnd, shift, isSigned);
6437     if (base.GetRegisterNumber() == RFP || base.GetRegisterNumber() == RSP) {
6438         memOp->SetStackMem(true);
6439     }
6440     return memOp;
6441 }
6442 
CreateMemOperand(MemOperand::AArch64AddressingMode mode,uint32 dSize,const MIRSymbol & sym)6443 MemOperand *AArch64CGFunc::CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 dSize, const MIRSymbol &sym)
6444 {
6445     auto *memOp = memPool->New<MemOperand>(mode, dSize, sym);
6446     return memOp;
6447 }
6448 
GenSaveMethodInfoCode(BB & bb)6449 void AArch64CGFunc::GenSaveMethodInfoCode(BB &bb)
6450 {
6451     if (GetCG()->UseFastUnwind()) {
6452         BB *formerCurBB = GetCurBB();
6453         GetDummyBB()->ClearInsns();
6454         SetCurBB(*GetDummyBB());
6455         if ((GetFunction().GetAttr(FUNCATTR_native) || GetFunction().GetAttr(FUNCATTR_fast_native)) &&
6456             !GetFunction().GetAttr(FUNCATTR_critical_native) && !GetFunction().GetAttr(FUNCATTR_bridge)) {
6457             RegOperand &fpReg = GetOrCreatePhysicalRegisterOperand(RFP, GetPointerSize() * kBitsPerByte, kRegTyInt);
6458 
6459             ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6460             RegOperand &parmRegOpnd1 = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, kRegTyInt);
6461             srcOpnds->PushOpnd(parmRegOpnd1);
6462             Operand &immOpnd = CreateImmOperand(0, k64BitSize, false);
6463             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadri64, parmRegOpnd1, immOpnd));
6464             RegOperand &parmRegOpnd2 = GetOrCreatePhysicalRegisterOperand(R1, k64BitSize, kRegTyInt);
6465             srcOpnds->PushOpnd(parmRegOpnd2);
6466             SelectCopy(parmRegOpnd2, PTY_a64, fpReg, PTY_a64);
6467 
6468             MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6469             std::string funcName("MCC_SetRiskyUnwindContext");
6470             sym->SetNameStrIdx(funcName);
6471 
6472             sym->SetStorageClass(kScText);
6473             sym->SetSKind(kStFunc);
6474             AppendCall(*sym, *srcOpnds);
6475             bb.SetHasCall();
6476         }
6477 
6478         bb.InsertAtBeginning(*GetDummyBB());
6479         SetCurBB(*formerCurBB);
6480     }
6481 }
6482 
HasStackLoadStore()6483 bool AArch64CGFunc::HasStackLoadStore()
6484 {
6485     FOR_ALL_BB(bb, this)
6486     {
6487         FOR_BB_INSNS(insn, bb)
6488         {
6489             uint32 opndNum = insn->GetOperandSize();
6490             for (uint32 i = 0; i < opndNum; ++i) {
6491                 Operand &opnd = insn->GetOperand(i);
6492                 if (opnd.IsMemoryAccessOperand()) {
6493                     auto &memOpnd = static_cast<MemOperand &>(opnd);
6494                     Operand *base = memOpnd.GetBaseRegister();
6495 
6496                     if ((base != nullptr) && base->IsRegister()) {
6497                         RegOperand *regOpnd = static_cast<RegOperand *>(base);
6498                         RegType regType = regOpnd->GetRegisterType();
6499                         uint32 regNO = regOpnd->GetRegisterNumber();
6500                         if (((regType != kRegTyCc) && ((regNO == RFP) || (regNO == RSP))) || (regType == kRegTyVary)) {
6501                             return true;
6502                         }
6503                     }
6504                 }
6505             }
6506         }
6507     }
6508     return false;
6509 }
6510 
GenerateYieldpoint(BB & bb)6511 void AArch64CGFunc::GenerateYieldpoint(BB &bb)
6512 {
6513     /* ldr wzr, [RYP]  # RYP hold address of the polling page. */
6514     auto &wzr = GetZeroOpnd(k32BitSize);
6515     auto &pollingPage = CreateMemOpnd(RYP, 0, k32BitSize);
6516     auto &yieldPoint = GetInsnBuilder()->BuildInsn(MOP_wldr, wzr, pollingPage);
6517     if (GetCG()->GenerateVerboseCG()) {
6518         yieldPoint.SetComment("yieldpoint");
6519     }
6520     bb.AppendInsn(yieldPoint);
6521 }
6522 
GetTargetRetOperand(PrimType primType,int32 sReg)6523 Operand &AArch64CGFunc::GetTargetRetOperand(PrimType primType, int32 sReg)
6524 {
6525     DEBUG_ASSERT(!IsInt128Ty(primType), "NIY");
6526     if (IsSpecialPseudoRegister(-sReg)) {
6527         return GetOrCreateSpecialRegisterOperand(sReg, primType);
6528     }
6529     bool useFpReg = !IsPrimitiveInteger(primType) || IsPrimitiveVectorFloat(primType);
6530     uint32 bitSize = GetPrimTypeBitSize(primType);
6531     bitSize = bitSize <= k32BitSize ? k32BitSize : bitSize;
6532     return GetOrCreatePhysicalRegisterOperand(useFpReg ? V0 : R0, bitSize, GetRegTyFromPrimTy(primType));
6533 }
6534 
CreateRegisterOperandOfType(PrimType primType)6535 RegOperand &AArch64CGFunc::CreateRegisterOperandOfType(PrimType primType)
6536 {
6537     RegType regType = GetRegTyFromPrimTy(primType);
6538     uint32 byteLength = GetPrimTypeSize(primType);
6539     return CreateRegisterOperandOfType(regType, byteLength);
6540 }
6541 
CreateRegisterOperandOfType(RegType regty,uint32 byteLen)6542 RegOperand &AArch64CGFunc::CreateRegisterOperandOfType(RegType regty, uint32 byteLen)
6543 {
6544     /* BUG: if half-precision floating point operations are supported? */
6545     /* AArch64 has 32-bit and 64-bit registers only */
6546     if (byteLen < k4ByteSize) {
6547         byteLen = k4ByteSize;
6548     }
6549     regno_t vRegNO = NewVReg(regty, byteLen);
6550     return CreateVirtualRegisterOperand(vRegNO);
6551 }
6552 
CreateRflagOperand()6553 RegOperand &AArch64CGFunc::CreateRflagOperand()
6554 {
6555     /* AArch64 has Status register that is 32-bit wide. */
6556     regno_t vRegNO = NewVRflag();
6557     return CreateVirtualRegisterOperand(vRegNO);
6558 }
6559 
MergeReturn()6560 void AArch64CGFunc::MergeReturn()
6561 {
6562     DEBUG_ASSERT(GetCurBB()->GetPrev()->GetFirstStmt() == GetCleanupLabel(), "must be");
6563 
6564     uint32 exitBBSize = GetExitBBsVec().size();
6565     if (exitBBSize == 0) {
6566         return;
6567     }
6568     if ((exitBBSize == 1) && GetExitBB(0) == GetCurBB()) {
6569         return;
6570     }
6571     if (exitBBSize == 1) {
6572         BB *onlyExitBB = GetExitBB(0);
6573         BB *onlyExitBBNext = onlyExitBB->GetNext();
6574         StmtNode *stmt = onlyExitBBNext->GetFirstStmt();
6575         /* only deal with the return_BB in the middle */
6576         if (stmt != GetCleanupLabel()) {
6577             LabelIdx labidx = CreateLabel();
6578             BB *retBB = CreateNewBB(labidx, onlyExitBB->IsUnreachable(), BB::kBBReturn, onlyExitBB->GetFrequency());
6579             onlyExitBB->AppendBB(*retBB);
6580             /* modify the original return BB. */
6581             DEBUG_ASSERT(onlyExitBB->GetKind() == BB::kBBReturn, "Error: suppose to merge multi return bb");
6582             onlyExitBB->SetKind(BB::kBBFallthru);
6583 
6584             GetExitBBsVec().pop_back();
6585             GetExitBBsVec().emplace_back(retBB);
6586             return;
6587         }
6588     }
6589 
6590     LabelIdx labidx = CreateLabel();
6591     LabelOperand &targetOpnd = GetOrCreateLabelOperand(labidx);
6592     uint32 freq = 0;
6593     for (auto *tmpBB : GetExitBBsVec()) {
6594         DEBUG_ASSERT(tmpBB->GetKind() == BB::kBBReturn, "Error: suppose to merge multi return bb");
6595         tmpBB->SetKind(BB::kBBGoto);
6596         tmpBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xuncond, targetOpnd));
6597         freq += tmpBB->GetFrequency();
6598     }
6599     BB *retBB = CreateNewBB(labidx, false, BB::kBBReturn, freq);
6600     GetCleanupBB()->PrependBB(*retBB);
6601 
6602     GetExitBBsVec().clear();
6603     GetExitBBsVec().emplace_back(retBB);
6604 }
6605 
HandleRetCleanup(NaryStmtNode & retNode)6606 void AArch64CGFunc::HandleRetCleanup(NaryStmtNode &retNode)
6607 {
6608     if (!GetCG()->GenLocalRC()) {
6609         /* handle local rc is disabled. */
6610         return;
6611     }
6612 
6613     constexpr uint8 opSize = 11;
6614     Opcode ops[opSize] = {OP_label, OP_goto,      OP_brfalse, OP_brtrue, OP_return, OP_call,
6615                           OP_icall, OP_rangegoto, OP_catch,   OP_try,    OP_endtry};
6616     std::set<Opcode> branchOp(ops, ops + opSize);
6617 
6618     /* get cleanup intrinsic */
6619     bool found = false;
6620     StmtNode *cleanupNode = retNode.GetPrev();
6621     cleanEANode = nullptr;
6622     while (cleanupNode != nullptr) {
6623         if (branchOp.find(cleanupNode->GetOpCode()) != branchOp.end()) {
6624             if (cleanupNode->GetOpCode() == OP_call) {
6625                 CallNode *callNode = static_cast<CallNode *>(cleanupNode);
6626                 MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx());
6627                 MIRSymbol *fsym = GetFunction().GetLocalOrGlobalSymbol(fn->GetStIdx(), false);
6628                 if ((fsym->GetName() == "MCC_DecRef_NaiveRCFast") || (fsym->GetName() == "MCC_IncRef_NaiveRCFast") ||
6629                     (fsym->GetName() == "MCC_IncDecRef_NaiveRCFast") || (fsym->GetName() == "MCC_LoadRefStatic") ||
6630                     (fsym->GetName() == "MCC_LoadRefField") || (fsym->GetName() == "MCC_LoadReferentField") ||
6631                     (fsym->GetName() == "MCC_LoadRefField_NaiveRCFast") ||
6632                     (fsym->GetName() == "MCC_LoadVolatileField") ||
6633                     (fsym->GetName() == "MCC_LoadVolatileStaticField") || (fsym->GetName() == "MCC_LoadWeakField") ||
6634                     (fsym->GetName() == "MCC_CheckObjMem")) {
6635                     cleanupNode = cleanupNode->GetPrev();
6636                     continue;
6637                 } else {
6638                     break;
6639                 }
6640             } else {
6641                 break;
6642             }
6643         }
6644 
6645         cleanupNode = cleanupNode->GetPrev();
6646     }
6647 
6648     if (!found) {
6649         MIRSymbol *retRef = nullptr;
6650         if (retNode.NumOpnds() != 0) {
6651             retRef = GetRetRefSymbol(*static_cast<NaryStmtNode &>(retNode).Opnd(0));
6652         }
6653         HandleRCCall(false, retRef);
6654     }
6655 }
6656 
GenRetCleanup(const IntrinsiccallNode * cleanupNode,bool forEA)6657 bool AArch64CGFunc::GenRetCleanup(const IntrinsiccallNode *cleanupNode, bool forEA)
6658 {
6659 #undef CC_DEBUG_INFO
6660 
6661 #ifdef CC_DEBUG_INFO
6662     LogInfo::MapleLogger() << "==============" << GetFunction().GetName() << "==============" << '\n';
6663 #endif
6664 
6665     if (cleanupNode == nullptr) {
6666         return false;
6667     }
6668 
6669     int32 minByteOffset = INT_MAX;
6670     int32 maxByteOffset = 0;
6671 
6672     int32 skipIndex = -1;
6673     MIRSymbol *skipSym = nullptr;
6674     size_t refSymNum = 0;
6675 
6676     /* now compute the offset range */
6677     std::vector<int32> offsets;
6678     AArch64MemLayout *memLayout = static_cast<AArch64MemLayout *>(this->GetMemlayout());
6679     for (size_t i = 0; i < refSymNum; ++i) {
6680         BaseNode *argExpr = cleanupNode->Opnd(i);
6681         CHECK_FATAL(argExpr->GetOpCode() == OP_dread, "should be dread");
6682         DreadNode *refNode = static_cast<DreadNode *>(argExpr);
6683         MIRSymbol *refSymbol = GetFunction().GetLocalOrGlobalSymbol(refNode->GetStIdx());
6684         if (memLayout->GetSymAllocTable().size() <= refSymbol->GetStIndex()) {
6685             ERR(kLncErr, "access memLayout->GetSymAllocTable() failed");
6686             return false;
6687         }
6688         AArch64SymbolAlloc *symLoc =
6689             static_cast<AArch64SymbolAlloc *>(memLayout->GetSymAllocInfo(refSymbol->GetStIndex()));
6690         int32 tempOffset = GetBaseOffset(*symLoc);
6691         offsets.emplace_back(tempOffset);
6692 #ifdef CC_DEBUG_INFO
6693         LogInfo::MapleLogger() << "refsym " << refSymbol->GetName() << " offset " << tempOffset << '\n';
6694 #endif
6695         minByteOffset = (minByteOffset > tempOffset) ? tempOffset : minByteOffset;
6696         maxByteOffset = (maxByteOffset < tempOffset) ? tempOffset : maxByteOffset;
6697     }
6698 
6699     /* get the skip offset */
6700     int32 skipOffset = -1;
6701     if (skipSym != nullptr) {
6702         AArch64SymbolAlloc *symLoc =
6703             static_cast<AArch64SymbolAlloc *>(memLayout->GetSymAllocInfo(skipSym->GetStIndex()));
6704         CHECK_FATAL(GetBaseOffset(*symLoc) < std::numeric_limits<int32>::max(), "out of range");
6705         skipOffset = GetBaseOffset(*symLoc);
6706         offsets.emplace_back(skipOffset);
6707 
6708 #ifdef CC_DEBUG_INFO
6709         LogInfo::MapleLogger() << "skip " << skipSym->GetName() << " offset " << skipOffset << '\n';
6710 #endif
6711 
6712         skipIndex = symLoc->GetOffset() / kAarch64OffsetAlign;
6713     }
6714 
6715     /* call runtime cleanup */
6716     if (minByteOffset < INT_MAX) {
6717         int32 refLocBase = memLayout->GetRefLocBaseLoc();
6718         uint32 refNum = memLayout->GetSizeOfRefLocals() / kAarch64OffsetAlign;
6719         CHECK_FATAL((static_cast<uint32_t>(refLocBase) + (refNum - 1) * kAarch64IntregBytelen) <
6720             static_cast<uint32_t>(std::numeric_limits<int32>::max()), "out of range");
6721         int32 refLocEnd = refLocBase + static_cast<int32>((refNum - 1) * kAarch64IntregBytelen);
6722         int32 realMin = minByteOffset < refLocBase ? refLocBase : minByteOffset;
6723         int32 realMax = maxByteOffset > refLocEnd ? refLocEnd : maxByteOffset;
6724         if (forEA) {
6725             std::sort(offsets.begin(), offsets.end());
6726             int32 prev = offsets[0];
6727             for (size_t i = 1; i < offsets.size(); i++) {
6728                 CHECK_FATAL((offsets[i] == prev) || ((offsets[i] - prev) == kAarch64IntregBytelen), "must be");
6729                 prev = offsets[i];
6730             }
6731             CHECK_FATAL((refLocBase - prev) == kAarch64IntregBytelen, "must be");
6732             realMin = minByteOffset;
6733             realMax = maxByteOffset;
6734         }
6735 #ifdef CC_DEBUG_INFO
6736         LogInfo::MapleLogger() << " realMin " << realMin << " realMax " << realMax << '\n';
6737 #endif
6738         if (realMax < realMin) {
6739             /* maybe there is a cleanup intrinsic bug, use CHECK_FATAL instead? */
6740             CHECK_FATAL(false, "must be");
6741         }
6742 
6743         /* optimization for little slot cleanup */
6744         if (realMax == realMin && !forEA) {
6745             RegOperand &phyOpnd = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6746             Operand &stackLoc = CreateStkTopOpnd(static_cast<uint32>(realMin), GetPointerSize() * kBitsPerByte);
6747             Insn &ldrInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_a64), phyOpnd, stackLoc);
6748             GetCurBB()->AppendInsn(ldrInsn);
6749 
6750             ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6751             srcOpnds->PushOpnd(phyOpnd);
6752             MIRSymbol *callSym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6753             std::string funcName("MCC_DecRef_NaiveRCFast");
6754             callSym->SetNameStrIdx(funcName);
6755             callSym->SetStorageClass(kScText);
6756             callSym->SetSKind(kStFunc);
6757             Insn &callInsn = AppendCall(*callSym, *srcOpnds);
6758             callInsn.SetRefSkipIdx(skipIndex);
6759             GetCurBB()->SetHasCall();
6760             /* because of return stmt is often the last stmt */
6761             GetCurBB()->SetFrequency(frequency);
6762 
6763             return true;
6764         }
6765         ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6766 
6767         ImmOperand &beginOpnd = CreateImmOperand(realMin, k64BitSize, true);
6768         regno_t vRegNO0 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
6769         RegOperand &vReg0 = CreateVirtualRegisterOperand(vRegNO0);
6770         RegOperand &fpOpnd = GetOrCreateStackBaseRegOperand();
6771         SelectAdd(vReg0, fpOpnd, beginOpnd, PTY_i64);
6772 
6773         RegOperand &parmRegOpnd1 = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6774         srcOpnds->PushOpnd(parmRegOpnd1);
6775         SelectCopy(parmRegOpnd1, PTY_a64, vReg0, PTY_a64);
6776 
6777         uint32 realRefNum = static_cast<uint32>((realMax - realMin) / kAarch64OffsetAlign + 1);
6778 
6779         ImmOperand &countOpnd = CreateImmOperand(realRefNum, k64BitSize, true);
6780 
6781         RegOperand &parmRegOpnd2 = GetOrCreatePhysicalRegisterOperand(R1, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6782         srcOpnds->PushOpnd(parmRegOpnd2);
6783         SelectCopyImm(parmRegOpnd2, countOpnd, PTY_i64);
6784 
6785         MIRSymbol *funcSym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6786         if ((skipSym != nullptr) && (skipOffset >= realMin) && (skipOffset <= realMax)) {
6787             /* call cleanupskip */
6788             uint32 stOffset = (skipOffset - realMin) / kAarch64OffsetAlign;
6789             ImmOperand &retLoc = CreateImmOperand(stOffset, k64BitSize, true);
6790 
6791             RegOperand &parmRegOpnd3 = GetOrCreatePhysicalRegisterOperand(R2, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6792             srcOpnds->PushOpnd(parmRegOpnd3);
6793             SelectCopyImm(parmRegOpnd3, retLoc, PTY_i64);
6794 
6795             std::string funcName;
6796             if (forEA) {
6797                 funcName = "MCC_CleanupNonRetEscObj";
6798             } else {
6799                 funcName = "MCC_CleanupLocalStackRefSkip_NaiveRCFast";
6800             }
6801             funcSym->SetNameStrIdx(funcName);
6802 #ifdef CC_DEBUG_INFO
6803             LogInfo::MapleLogger() << "num " << real_ref_num << " skip loc " << stOffset << '\n';
6804 #endif
6805         } else {
6806             /* call cleanup */
6807             CHECK_FATAL(!forEA, "must be");
6808             std::string funcName("MCC_CleanupLocalStackRef_NaiveRCFast");
6809             funcSym->SetNameStrIdx(funcName);
6810 #ifdef CC_DEBUG_INFO
6811             LogInfo::MapleLogger() << "num " << real_ref_num << '\n';
6812 #endif
6813         }
6814 
6815         funcSym->SetStorageClass(kScText);
6816         funcSym->SetSKind(kStFunc);
6817         Insn &callInsn = AppendCall(*funcSym, *srcOpnds);
6818         callInsn.SetRefSkipIdx(skipIndex);
6819         GetCurBB()->SetHasCall();
6820         GetCurBB()->SetFrequency(frequency);
6821     }
6822     return true;
6823 }
6824 
CreateVirtualRegisterOperand(regno_t vRegNO,uint32 size,RegType kind,uint32 flg) const6825 RegOperand *AArch64CGFunc::CreateVirtualRegisterOperand(regno_t vRegNO, uint32 size, RegType kind, uint32 flg) const
6826 {
6827     RegOperand *res = memPool->New<RegOperand>(vRegNO, size, kind, flg);
6828     maplebe::VregInfo::vRegOperandTable[vRegNO] = res;
6829     return res;
6830 }
6831 
CreateVirtualRegisterOperand(regno_t vRegNO)6832 RegOperand &AArch64CGFunc::CreateVirtualRegisterOperand(regno_t vRegNO)
6833 {
6834     DEBUG_ASSERT((vReg.vRegOperandTable.find(vRegNO) == vReg.vRegOperandTable.end()), "already exist");
6835     DEBUG_ASSERT(vRegNO < vReg.VRegTableSize(), "index out of range");
6836     uint8 bitSize = static_cast<uint8>((static_cast<uint32>(vReg.VRegTableGetSize(vRegNO))) * kBitsPerByte);
6837     RegOperand *res = CreateVirtualRegisterOperand(vRegNO, bitSize, vReg.VRegTableGetType(vRegNO));
6838     return *res;
6839 }
6840 
GetOrCreateVirtualRegisterOperand(regno_t vRegNO)6841 RegOperand &AArch64CGFunc::GetOrCreateVirtualRegisterOperand(regno_t vRegNO)
6842 {
6843     auto it = maplebe::VregInfo::vRegOperandTable.find(vRegNO);
6844     return (it != maplebe::VregInfo::vRegOperandTable.end()) ? *(it->second) : CreateVirtualRegisterOperand(vRegNO);
6845 }
6846 
GetOrCreateVirtualRegisterOperand(RegOperand & regOpnd)6847 RegOperand &AArch64CGFunc::GetOrCreateVirtualRegisterOperand(RegOperand &regOpnd)
6848 {
6849     regno_t regNO = regOpnd.GetRegisterNumber();
6850     auto it = maplebe::VregInfo::vRegOperandTable.find(regNO);
6851     if (it != maplebe::VregInfo::vRegOperandTable.end()) {
6852         it->second->SetSize(regOpnd.GetSize());
6853         it->second->SetRegisterNumber(regNO);
6854         it->second->SetRegisterType(regOpnd.GetRegisterType());
6855         it->second->SetValidBitsNum(regOpnd.GetValidBitsNum());
6856         return *it->second;
6857     } else {
6858         auto *newRegOpnd = static_cast<RegOperand *>(regOpnd.Clone(*memPool));
6859         regno_t newRegNO = newRegOpnd->GetRegisterNumber();
6860         if (newRegNO >= GetMaxRegNum()) {
6861             SetMaxRegNum(newRegNO + kRegIncrStepLen);
6862             vReg.VRegTableResize(GetMaxRegNum());
6863         }
6864         maplebe::VregInfo::vRegOperandTable[newRegNO] = newRegOpnd;
6865         VirtualRegNode *vregNode = memPool->New<VirtualRegNode>(newRegOpnd->GetRegisterType(), newRegOpnd->GetSize());
6866         vReg.VRegTableElementSet(newRegNO, vregNode);
6867         vReg.SetCount(GetMaxRegNum());
6868         return *newRegOpnd;
6869     }
6870 }
6871 
HandleRCCall(bool begin,const MIRSymbol * retRef)6872 void AArch64CGFunc::HandleRCCall(bool begin, const MIRSymbol *retRef)
6873 {
6874     if (!GetCG()->GenLocalRC() && !begin) {
6875         /* handle local rc is disabled. */
6876         return;
6877     }
6878 
6879     AArch64MemLayout *memLayout = static_cast<AArch64MemLayout *>(this->GetMemlayout());
6880     int32 refNum = static_cast<int32>(memLayout->GetSizeOfRefLocals() / kAarch64OffsetAlign);
6881     if (!refNum) {
6882         if (begin) {
6883             GenerateYieldpoint(*GetCurBB());
6884             yieldPointInsn = GetCurBB()->GetLastInsn();
6885         }
6886         return;
6887     }
6888 
6889     /* no MCC_CleanupLocalStackRefSkip when ret_ref is the only ref symbol */
6890     if ((refNum == 1) && (retRef != nullptr)) {
6891         if (begin) {
6892             GenerateYieldpoint(*GetCurBB());
6893             yieldPointInsn = GetCurBB()->GetLastInsn();
6894         }
6895         return;
6896     }
6897     CHECK_FATAL(refNum < 0xFFFF, "not enough room for size.");
6898     int32 refLocBase = memLayout->GetRefLocBaseLoc();
6899     CHECK_FATAL((refLocBase >= 0) && (refLocBase < 0xFFFF), "not enough room for offset.");
6900     int32 formalRef = 0;
6901     /* avoid store zero to formal localrefvars. */
6902     if (begin) {
6903         for (uint32 i = 0; i < GetFunction().GetFormalCount(); ++i) {
6904             if (GetFunction().GetNthParamAttr(i).GetAttr(ATTR_localrefvar)) {
6905                 refNum--;
6906                 formalRef++;
6907             }
6908         }
6909     }
6910     /*
6911      * if the number of local refvar is less than 12, use stp or str to init local refvar
6912      * else call function MCC_InitializeLocalStackRef to init.
6913      */
6914     if (begin && (refNum <= kRefNum12) &&
6915         ((refLocBase + kAarch64IntregBytelen * (refNum - 1)) < kStpLdpImm64UpperBound)) {
6916         int32 pairNum = refNum / kDivide2;
6917         int32 singleNum = refNum % kDivide2;
6918         const int32 pairRefBytes = 16; /* the size of each pair of ref is 16 bytes */
6919         int32 ind = 0;
6920         while (ind < pairNum) {
6921             int32 offset = memLayout->GetRefLocBaseLoc() + kAarch64IntregBytelen * formalRef + pairRefBytes * ind;
6922             Operand &zeroOp = GetZeroOpnd(k64BitSize);
6923             Operand &stackLoc = CreateStkTopOpnd(static_cast<uint32>(offset), GetPointerSize() * kBitsPerByte);
6924             Insn &setInc = GetInsnBuilder()->BuildInsn(MOP_xstp, zeroOp, zeroOp, stackLoc);
6925             GetCurBB()->AppendInsn(setInc);
6926             ind++;
6927         }
6928         if (singleNum > 0) {
6929             int32 offset = memLayout->GetRefLocBaseLoc() + kAarch64IntregBytelen * formalRef +
6930                            kAarch64IntregBytelen * (refNum - 1);
6931             Operand &zeroOp = GetZeroOpnd(k64BitSize);
6932             Operand &stackLoc = CreateStkTopOpnd(static_cast<uint32>(offset), GetPointerSize() * kBitsPerByte);
6933             Insn &setInc = GetInsnBuilder()->BuildInsn(MOP_xstr, zeroOp, stackLoc);
6934             GetCurBB()->AppendInsn(setInc);
6935         }
6936         /* Insert Yield Point just after localrefvar are initialized. */
6937         GenerateYieldpoint(*GetCurBB());
6938         yieldPointInsn = GetCurBB()->GetLastInsn();
6939         return;
6940     }
6941 
6942     /* refNum is 1 and refvar is not returned, this refvar need to call MCC_DecRef_NaiveRCFast. */
6943     if ((refNum == 1) && !begin && (retRef == nullptr)) {
6944         RegOperand &phyOpnd = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6945         Operand &stackLoc =
6946             CreateStkTopOpnd(static_cast<uint32>(memLayout->GetRefLocBaseLoc()), GetPointerSize() * kBitsPerByte);
6947         Insn &ldrInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_a64), phyOpnd, stackLoc);
6948         GetCurBB()->AppendInsn(ldrInsn);
6949 
6950         ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6951         srcOpnds->PushOpnd(phyOpnd);
6952         MIRSymbol *callSym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6953         std::string funcName("MCC_DecRef_NaiveRCFast");
6954         callSym->SetNameStrIdx(funcName);
6955         callSym->SetStorageClass(kScText);
6956         callSym->SetSKind(kStFunc);
6957 
6958         AppendCall(*callSym, *srcOpnds);
6959         GetCurBB()->SetHasCall();
6960         if (frequency != 0) {
6961             GetCurBB()->SetFrequency(frequency);
6962         }
6963         return;
6964     }
6965 
6966     /* refNum is 2 and one of refvar is returned, only another one is needed to call MCC_DecRef_NaiveRCFast. */
6967     if ((refNum == 2) && !begin && retRef != nullptr) {
6968         AArch64SymbolAlloc *symLoc =
6969             static_cast<AArch64SymbolAlloc *>(memLayout->GetSymAllocInfo(retRef->GetStIndex()));
6970         int32 stOffset = symLoc->GetOffset() / kAarch64OffsetAlign;
6971         RegOperand &phyOpnd = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
6972         Operand *stackLoc = nullptr;
6973         if (stOffset == 0) {
6974             /* just have to Dec the next one. */
6975             stackLoc = &CreateStkTopOpnd(static_cast<uint32>(memLayout->GetRefLocBaseLoc()) + kAarch64IntregBytelen,
6976                                          GetPointerSize() * kBitsPerByte);
6977         } else {
6978             /* just have to Dec the current one. */
6979             stackLoc =
6980                 &CreateStkTopOpnd(static_cast<uint32>(memLayout->GetRefLocBaseLoc()), GetPointerSize() * kBitsPerByte);
6981         }
6982         Insn &ldrInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_a64), phyOpnd, *stackLoc);
6983         GetCurBB()->AppendInsn(ldrInsn);
6984 
6985         ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
6986         srcOpnds->PushOpnd(phyOpnd);
6987         MIRSymbol *callSym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
6988         std::string funcName("MCC_DecRef_NaiveRCFast");
6989         callSym->SetNameStrIdx(funcName);
6990         callSym->SetStorageClass(kScText);
6991         callSym->SetSKind(kStFunc);
6992         Insn &callInsn = AppendCall(*callSym, *srcOpnds);
6993         callInsn.SetRefSkipIdx(stOffset);
6994         GetCurBB()->SetHasCall();
6995         if (frequency != 0) {
6996             GetCurBB()->SetFrequency(frequency);
6997         }
6998         return;
6999     }
7000 
7001     bool needSkip = false;
7002     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
7003 
7004     ImmOperand *beginOpnd =
7005         &CreateImmOperand(memLayout->GetRefLocBaseLoc() + kAarch64IntregBytelen * formalRef, k64BitSize, true);
7006     ImmOperand *countOpnd = &CreateImmOperand(refNum, k64BitSize, true);
7007     int32 refSkipIndex = -1;
7008     if (!begin && retRef != nullptr) {
7009         AArch64SymbolAlloc *symLoc =
7010             static_cast<AArch64SymbolAlloc *>(memLayout->GetSymAllocInfo(retRef->GetStIndex()));
7011         int32 stOffset = symLoc->GetOffset() / kAarch64OffsetAlign;
7012         refSkipIndex = stOffset;
7013         if (stOffset == 0) {
7014             /* ret_ref at begin. */
7015             beginOpnd = &CreateImmOperand(memLayout->GetRefLocBaseLoc() + kAarch64IntregBytelen, k64BitSize, true);
7016             countOpnd = &CreateImmOperand(refNum - 1, k64BitSize, true);
7017         } else if (stOffset == (refNum - 1)) {
7018             /* ret_ref at end. */
7019             countOpnd = &CreateImmOperand(refNum - 1, k64BitSize, true);
7020         } else {
7021             needSkip = true;
7022         }
7023     }
7024 
7025     regno_t vRegNO0 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
7026     RegOperand &vReg0 = CreateVirtualRegisterOperand(vRegNO0);
7027     RegOperand &fpOpnd = GetOrCreateStackBaseRegOperand();
7028     SelectAdd(vReg0, fpOpnd, *beginOpnd, PTY_i64);
7029 
7030     RegOperand &parmRegOpnd1 = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
7031     srcOpnds->PushOpnd(parmRegOpnd1);
7032     SelectCopy(parmRegOpnd1, PTY_a64, vReg0, PTY_a64);
7033 
7034     regno_t vRegNO1 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
7035     RegOperand &vReg1 = CreateVirtualRegisterOperand(vRegNO1);
7036     SelectCopyImm(vReg1, *countOpnd, PTY_i64);
7037 
7038     RegOperand &parmRegOpnd2 = GetOrCreatePhysicalRegisterOperand(R1, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
7039     srcOpnds->PushOpnd(parmRegOpnd2);
7040     SelectCopy(parmRegOpnd2, PTY_a64, vReg1, PTY_a64);
7041 
7042     MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
7043     if (begin) {
7044         std::string funcName("MCC_InitializeLocalStackRef");
7045         sym->SetNameStrIdx(funcName);
7046         CHECK_FATAL(countOpnd->GetValue() > 0, "refCount should be greater than 0.");
7047         refCount = static_cast<uint32>(countOpnd->GetValue());
7048         beginOffset = beginOpnd->GetValue();
7049     } else if (!needSkip) {
7050         std::string funcName("MCC_CleanupLocalStackRef_NaiveRCFast");
7051         sym->SetNameStrIdx(funcName);
7052     } else {
7053         CHECK_NULL_FATAL(retRef);
7054         if (retRef->GetStIndex() >= memLayout->GetSymAllocTable().size()) {
7055             CHECK_FATAL(false, "index out of range in AArch64CGFunc::HandleRCCall");
7056         }
7057         AArch64SymbolAlloc *symLoc =
7058             static_cast<AArch64SymbolAlloc *>(memLayout->GetSymAllocInfo(retRef->GetStIndex()));
7059         int32 stOffset = symLoc->GetOffset() / kAarch64OffsetAlign;
7060         ImmOperand &retLoc = CreateImmOperand(stOffset, k64BitSize, true);
7061 
7062         regno_t vRegNO2 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
7063         RegOperand &vReg2 = CreateVirtualRegisterOperand(vRegNO2);
7064         SelectCopyImm(vReg2, retLoc, PTY_i64);
7065 
7066         RegOperand &parmRegOpnd3 = GetOrCreatePhysicalRegisterOperand(R2, k64BitSize, GetRegTyFromPrimTy(PTY_a64));
7067         srcOpnds->PushOpnd(parmRegOpnd3);
7068         SelectCopy(parmRegOpnd3, PTY_a64, vReg2, PTY_a64);
7069 
7070         std::string funcName("MCC_CleanupLocalStackRefSkip_NaiveRCFast");
7071         sym->SetNameStrIdx(funcName);
7072     }
7073     sym->SetStorageClass(kScText);
7074     sym->SetSKind(kStFunc);
7075 
7076     Insn &callInsn = AppendCall(*sym, *srcOpnds);
7077     callInsn.SetRefSkipIdx(refSkipIndex);
7078     if (frequency != 0) {
7079         GetCurBB()->SetFrequency(frequency);
7080     }
7081     GetCurBB()->SetHasCall();
7082     if (begin) {
7083         /* Insert Yield Point just after localrefvar are initialized. */
7084         GenerateYieldpoint(*GetCurBB());
7085         yieldPointInsn = GetCurBB()->GetLastInsn();
7086     }
7087 }
7088 
SelectLibMemCopy(RegOperand & destOpnd,RegOperand & srcOpnd,uint32 structSize)7089 void AArch64CGFunc::SelectLibMemCopy(RegOperand &destOpnd, RegOperand &srcOpnd, uint32 structSize)
7090 {
7091     std::vector<Operand *> opndVec;
7092     opndVec.push_back(&CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)));  // result
7093     opndVec.push_back(&destOpnd);                                                      // param 0
7094     opndVec.push_back(&srcOpnd);                                                       // param 1
7095     opndVec.push_back(&CreateImmOperand(structSize, k64BitSize, false));               // param 2
7096     SelectLibCall("memcpy", opndVec, PTY_a64, PTY_a64);
7097 }
7098 
SelectInsnMemCopy(const MemOperand & destOpnd,const MemOperand & srcOpnd,uint32 size,bool isRefField,BaseNode * destNode,BaseNode * srcNode)7099 void AArch64CGFunc::SelectInsnMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size,
7100                                       bool isRefField, BaseNode *destNode, BaseNode *srcNode)
7101 {
7102     auto createMemCopy = [this, isRefField, destNode, srcNode](MemOperand &dest, MemOperand &src, uint32 byteSize) {
7103         Insn *ldInsn = nullptr;
7104         Insn *stInsn = nullptr;
7105 
7106         if (byteSize == k16ByteSize) {  // ldp/stp
7107             auto &tmpOpnd1 = CreateRegisterOperandOfType(PTY_u64);
7108             auto &tmpOpnd2 = CreateRegisterOperandOfType(PTY_u64);
7109             // ldr srcMem to tmpReg
7110             ldInsn = &GetInsnBuilder()->BuildInsn(MOP_xldp, tmpOpnd1, tmpOpnd2, src);
7111             // str tempReg to destMem
7112             stInsn = &GetInsnBuilder()->BuildInsn(MOP_xstp, tmpOpnd1, tmpOpnd2, dest);
7113         } else {
7114             PrimType primType =
7115                 (byteSize == k8ByteSize)
7116                     ? PTY_u64
7117                     : (byteSize == k4ByteSize)
7118                           ? PTY_u32
7119                           : (byteSize == k2ByteSize) ? PTY_u16 : (byteSize == k1ByteSize) ? PTY_u8 : PTY_unknown;
7120             DEBUG_ASSERT(primType != PTY_unknown, "NIY, unkown byte size");
7121             auto &tmpOpnd = CreateRegisterOperandOfType(kRegTyInt, byteSize);
7122             // ldr srcMem to tmpReg
7123             ldInsn = &GetInsnBuilder()->BuildInsn(PickLdInsn(byteSize * kBitsPerByte, primType), tmpOpnd, src);
7124             // str tempReg to destMem
7125             stInsn = &GetInsnBuilder()->BuildInsn(PickStInsn(byteSize * kBitsPerByte, primType), tmpOpnd, dest);
7126         }
7127         // Set memory reference info
7128         SetMemReferenceOfInsn(*ldInsn, srcNode);
7129         ldInsn->MarkAsAccessRefField(isRefField);
7130         GetCurBB()->AppendInsn(*ldInsn);
7131         if (!VERIFY_INSN(ldInsn)) {
7132             SPLIT_INSN(ldInsn, this);
7133         }
7134 
7135         // Set memory reference info
7136         SetMemReferenceOfInsn(*stInsn, destNode);
7137         GetCurBB()->AppendInsn(*stInsn);
7138         if (!VERIFY_INSN(stInsn)) {
7139             SPLIT_INSN(stInsn, this);
7140         }
7141     };
7142 
7143     // Insn can be reduced when sizeNotCoverd = 3 | 5 | 6 | 7
7144     for (uint32 offset = 0; offset < size;) {
7145         auto sizeNotCoverd = size - offset;
7146         uint32 copyByteSize = 0;
7147         if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li &&
7148             srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li &&
7149             sizeNotCoverd >= k16ByteSize) {  // ldp/stp unsupport lo12li mem
7150             copyByteSize = k16ByteSize;
7151         } else if (sizeNotCoverd >= k8ByteSize) {
7152             copyByteSize = k8ByteSize;
7153         } else if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li &&
7154                    srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && sizeNotCoverd > k4ByteSize &&
7155                    offset >= k8ByteSize - sizeNotCoverd) {
7156             copyByteSize = k8ByteSize;  // 5: w + b -> x ; 6: w + h -> x ; 7: w + h + b -> x
7157             offset -= (k8ByteSize - sizeNotCoverd);
7158         } else if (sizeNotCoverd >= k4ByteSize) {
7159             copyByteSize = k4ByteSize;
7160         } else if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li &&
7161                    srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && sizeNotCoverd > k2ByteSize &&
7162                    offset >= k4ByteSize - sizeNotCoverd) {
7163             copyByteSize = k4ByteSize;  // 3: h + b -> w
7164             offset -= (k4ByteSize - sizeNotCoverd);
7165         } else if (sizeNotCoverd >= k2ByteSize) {
7166             copyByteSize = k2ByteSize;
7167         } else {
7168             copyByteSize = k1ByteSize;
7169         }
7170 
7171         auto &srcMem = GetMemOperandAddOffset(srcOpnd, offset, copyByteSize * kBitsPerByte);
7172         auto &destMem = GetMemOperandAddOffset(destOpnd, offset, copyByteSize * kBitsPerByte);
7173         createMemCopy(destMem, srcMem, copyByteSize);
7174 
7175         offset += copyByteSize;
7176     }
7177 }
7178 
SelectMemCopy(const MemOperand & destOpnd,const MemOperand & srcOpnd,uint32 size,bool isRefField,BaseNode * destNode,BaseNode * srcNode)7179 void AArch64CGFunc::SelectMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size, bool isRefField,
7180                                   BaseNode *destNode, BaseNode *srcNode)
7181 {
7182     if (size > kParmMemcpySize) {
7183         CHECK_NULL_FATAL(ExtractMemBaseAddr(srcOpnd));
7184         SelectLibMemCopy(*ExtractMemBaseAddr(destOpnd), *ExtractMemBaseAddr(srcOpnd), size);
7185         return;
7186     }
7187     SelectInsnMemCopy(destOpnd, srcOpnd, size, isRefField, destNode, srcNode);
7188 }
7189 
SelectParmListPreprocessForAggregate(BaseNode & argExpr,int32 & structCopyOffset,std::vector<ParamDesc> & argsDesc,bool isArgUnused)7190 void AArch64CGFunc::SelectParmListPreprocessForAggregate(BaseNode &argExpr, int32 &structCopyOffset,
7191                                                          std::vector<ParamDesc> &argsDesc, bool isArgUnused)
7192 {
7193     MemRWNodeHelper memHelper(argExpr, GetFunction(), GetBecommon());
7194     auto mirSize = memHelper.GetMemSize();
7195     if (mirSize <= k16BitSize) {
7196         argsDesc.emplace_back(memHelper.GetMIRType(), &argExpr, memHelper.GetByteOffset());
7197         return;
7198     }
7199 
7200     PrimType baseType = PTY_begin;
7201     size_t elemNum = 0;
7202     if (IsHomogeneousAggregates(*memHelper.GetMIRType(), baseType, elemNum)) {
7203         // B.3 If the argument type is an HFA or an HVA, then the argument is used unmodified.
7204         argsDesc.emplace_back(memHelper.GetMIRType(), &argExpr, memHelper.GetByteOffset());
7205         return;
7206     }
7207 
7208     // B.4  If the argument type is a Composite Type that is larger than 16 bytes,
7209     //      then the argument is copied to memory allocated by the caller
7210     //      and the argument is replaced by a pointer to the copy.
7211     structCopyOffset = static_cast<int32>(RoundUp(static_cast<uint32>(structCopyOffset), k8ByteSize));
7212 
7213     // pre copy
7214     auto *rhsMemOpnd = SelectRhsMemOpnd(argExpr);
7215     if (!isArgUnused) {
7216         auto &spReg = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt);
7217         auto &offsetOpnd = CreateImmOperand(structCopyOffset, k64BitSize, false);
7218         auto *destMemOpnd = CreateMemOperand(k64BitSize, spReg, offsetOpnd, false);
7219 
7220         auto copySize = CGOptions::IsBigEndian() ? static_cast<uint32>(RoundUp(mirSize, k8ByteSize)) : mirSize;
7221         SelectMemCopy(*destMemOpnd, *rhsMemOpnd, copySize);
7222     }
7223 
7224     (void)argsDesc.emplace_back(memHelper.GetMIRType(), nullptr, static_cast<uint32>(structCopyOffset), true);
7225     structCopyOffset += static_cast<int32>(RoundUp(mirSize, k8ByteSize));
7226 }
7227 
7228 // Stage B - Pre-padding and extension of arguments
SelectParmListPreprocess(StmtNode & naryNode,size_t start,std::vector<ParamDesc> & argsDesc,const MIRFunction * callee)7229 bool AArch64CGFunc::SelectParmListPreprocess(StmtNode &naryNode, size_t start, std::vector<ParamDesc> &argsDesc,
7230                                              const MIRFunction *callee)
7231 {
7232     bool hasSpecialArg = false;
7233     int32 structCopyOffset = GetMaxParamStackSize() - GetStructCopySize();
7234     for (size_t i = start; i < naryNode.NumOpnds(); ++i) {
7235         BaseNode *argExpr = naryNode.Opnd(i);
7236         DEBUG_ASSERT(argExpr != nullptr, "not null check");
7237         PrimType primType = argExpr->GetPrimType();
7238         DEBUG_ASSERT(primType != PTY_void, "primType should not be void");
7239         if (primType == PTY_agg) {
7240             SelectParmListPreprocessForAggregate(*argExpr, structCopyOffset, argsDesc,
7241                                                  (callee && callee->GetFuncDesc().IsArgUnused(i)));
7242         } else {
7243             auto *mirType = GlobalTables::GetTypeTable().GetPrimType(primType);
7244             (void)argsDesc.emplace_back(mirType, argExpr);
7245         }
7246 
7247         if (MarkParmListCall(*argExpr)) {
7248             argsDesc.rbegin()->isSpecialArg = true;
7249             hasSpecialArg = true;
7250         }
7251     }
7252     return hasSpecialArg;
7253 }
7254 
GetCalleeFunction(StmtNode & naryNode) const7255 std::pair<MIRFunction *, MIRFuncType *> AArch64CGFunc::GetCalleeFunction(StmtNode &naryNode) const
7256 {
7257     MIRFunction *callee = nullptr;
7258     MIRFuncType *calleeType = nullptr;
7259     if (dynamic_cast<CallNode *>(&naryNode) != nullptr) {
7260         auto calleePuIdx = static_cast<CallNode &>(naryNode).GetPUIdx();
7261         callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(calleePuIdx);
7262         calleeType = callee->GetMIRFuncType();
7263     } else if (naryNode.GetOpCode() == OP_icallproto) {
7264         auto *iCallNode = &static_cast<IcallNode &>(naryNode);
7265         MIRType *protoType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iCallNode->GetRetTyIdx());
7266         if (protoType->IsMIRPtrType()) {
7267             calleeType = static_cast<MIRPtrType *>(protoType)->GetPointedFuncType();
7268         } else if (protoType->IsMIRFuncType()) {
7269             calleeType = static_cast<MIRFuncType *>(protoType);
7270         }
7271     }
7272     return {callee, calleeType};
7273 }
7274 
SelectParmListSmallStruct(const MIRType & mirType,const CCLocInfo & ploc,Operand & addr,ListOperand & srcOpnds,bool isSpecialArg,std::vector<RegMapForPhyRegCpy> & regMapForTmpBB)7275 void AArch64CGFunc::SelectParmListSmallStruct(const MIRType &mirType, const CCLocInfo &ploc, Operand &addr,
7276                                               ListOperand &srcOpnds, bool isSpecialArg,
7277                                               std::vector<RegMapForPhyRegCpy> &regMapForTmpBB)
7278 {
7279     uint32 offset = 0;
7280     DEBUG_ASSERT(addr.IsMemoryAccessOperand(), "NIY, must be mem opnd");
7281     uint64 size = mirType.GetSize();
7282     auto &memOpnd = static_cast<MemOperand &>(addr);
7283     // ldr memOpnd to parmReg
7284     auto loadParamFromMem = [this, &offset, &memOpnd, &srcOpnds, &size, isSpecialArg,
7285                              &regMapForTmpBB](AArch64reg regno, PrimType primType) {
7286         auto &phyReg =
7287             GetOrCreatePhysicalRegisterOperand(regno, GetPrimTypeBitSize(primType), GetRegTyFromPrimTy(primType));
7288         bool isFpReg = !IsPrimitiveInteger(primType) || IsPrimitiveVectorFloat(primType);
7289         if (!CGOptions::IsBigEndian() && !isFpReg && (size - offset < k8ByteSize)) {
7290             // load exact size agg (BigEndian not support yet)
7291             RegOperand *valOpnd = nullptr;
7292             for (uint32 exactOfst = 0; exactOfst < (size - offset);) {
7293                 PrimType exactPrimType;
7294                 auto loadSize = size - offset - exactOfst;
7295                 if (loadSize >= k4ByteSize) {
7296                     exactPrimType = PTY_u32;
7297                 } else if (loadSize >= k2ByteSize) {
7298                     exactPrimType = PTY_u16;
7299                 } else {
7300                     exactPrimType = PTY_u8;
7301                 }
7302                 auto ldBitSize = GetPrimTypeBitSize(exactPrimType);
7303                 auto *ldOpnd = &GetMemOperandAddOffset(memOpnd, exactOfst + offset, ldBitSize);
7304                 auto ldMop = PickLdInsn(ldBitSize, exactPrimType);
7305                 auto &tmpValOpnd = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, GetPrimTypeSize(exactPrimType)));
7306                 Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, tmpValOpnd, *ldOpnd);
7307                 GetCurBB()->AppendInsn(ldInsn);
7308                 if (!VERIFY_INSN(&ldInsn)) {
7309                     SPLIT_INSN(&ldInsn, this);
7310                 }
7311 
7312                 if (exactOfst != 0) {
7313                     auto &shiftOpnd = CreateImmOperand(exactOfst * kBitsPerByte, k32BitSize, false);
7314                     SelectShift(tmpValOpnd, tmpValOpnd, shiftOpnd, kShiftLeft, primType);
7315                 }
7316                 if (valOpnd) {
7317                     SelectBior(*valOpnd, *valOpnd, tmpValOpnd, primType);
7318                 } else {
7319                     valOpnd = &tmpValOpnd;
7320                 }
7321                 exactOfst += GetPrimTypeSize(exactPrimType);
7322             }
7323             if (isSpecialArg) {
7324                 regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&phyReg, primType, valOpnd, primType));
7325             } else {
7326                 SelectCopy(phyReg, primType, *valOpnd, primType);
7327             }
7328         } else {
7329             auto *ldOpnd = &GetMemOperandAddOffset(memOpnd, offset, GetPrimTypeBitSize(primType));
7330             auto ldMop = PickLdInsn(GetPrimTypeBitSize(primType), primType);
7331             if (isSpecialArg) {
7332                 RegOperand *tmpReg = &CreateRegisterOperandOfType(primType);
7333                 Insn &tmpLdInsn = GetInsnBuilder()->BuildInsn(ldMop, *tmpReg, *ldOpnd);
7334                 regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&phyReg, primType, tmpReg, primType));
7335                 GetCurBB()->AppendInsn(tmpLdInsn);
7336                 if (!VERIFY_INSN(&tmpLdInsn)) {
7337                     SPLIT_INSN(&tmpLdInsn, this);
7338                 }
7339             } else {
7340                 Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, phyReg, *ldOpnd);
7341                 GetCurBB()->AppendInsn(ldInsn);
7342                 if (!VERIFY_INSN(&ldInsn)) {
7343                     SPLIT_INSN(&ldInsn, this);
7344                 }
7345             }
7346         }
7347         srcOpnds.PushOpnd(phyReg);
7348         offset += GetPrimTypeSize(primType);
7349     };
7350     loadParamFromMem(static_cast<AArch64reg>(ploc.reg0), ploc.primTypeOfReg0);
7351     if (ploc.reg1 != kRinvalid) {
7352         loadParamFromMem(static_cast<AArch64reg>(ploc.reg1), ploc.primTypeOfReg1);
7353     }
7354     if (ploc.reg2 != kRinvalid) {
7355         loadParamFromMem(static_cast<AArch64reg>(ploc.reg2), ploc.primTypeOfReg2);
7356     }
7357     if (ploc.reg3 != kRinvalid) {
7358         loadParamFromMem(static_cast<AArch64reg>(ploc.reg3), ploc.primTypeOfReg3);
7359     }
7360 }
7361 
SelectParmListPassByStack(const MIRType & mirType,Operand & opnd,uint32 memOffset,bool preCopyed,std::vector<Insn * > & insnForStackArgs)7362 void AArch64CGFunc::SelectParmListPassByStack(const MIRType &mirType, Operand &opnd, uint32 memOffset, bool preCopyed,
7363                                               std::vector<Insn *> &insnForStackArgs)
7364 {
7365     if (!preCopyed && mirType.GetPrimType() == PTY_agg) {
7366         DEBUG_ASSERT(opnd.IsMemoryAccessOperand(), "NIY, must be mem opnd");
7367         auto &actOpnd = CreateMemOpnd(RSP, memOffset, k64BitSize);
7368         auto mirSize = CGOptions::IsBigEndian() ? static_cast<uint32>(RoundUp(mirType.GetSize(), k8ByteSize))
7369                                                 : static_cast<uint32>(mirType.GetSize());
7370         // can't use libmemcpy, it will modify parm reg
7371         SelectInsnMemCopy(actOpnd, static_cast<MemOperand &>(opnd), mirSize);
7372         return;
7373     }
7374 
7375     if (IsInt128Ty(mirType.GetPrimType())) {
7376         DEBUG_ASSERT(!preCopyed, "NIY");
7377         MemOperand &mem = CreateMemOpnd(RSP, memOffset, GetPrimTypeBitSize(PTY_u128));
7378         mem.SetStackArgMem(true);
7379         SelectCopy(mem, PTY_u128, opnd, PTY_u128);
7380         return;
7381     }
7382 
7383     PrimType primType = preCopyed ? PTY_a64 : mirType.GetPrimType();
7384     CHECK_FATAL(primType != PTY_i128 && primType != PTY_u128, "NIY, i128 is unsupported");
7385     auto &valReg = LoadIntoRegister(opnd, primType);
7386     auto &actMemOpnd = CreateMemOpnd(RSP, memOffset, GetPrimTypeBitSize(primType));
7387     Insn &strInsn = GetInsnBuilder()->BuildInsn(PickStInsn(GetPrimTypeBitSize(primType), primType), valReg, actMemOpnd);
7388     actMemOpnd.SetStackArgMem(true);
7389     if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel2 && insnForStackArgs.size() < kShiftAmount12) {
7390         (void)insnForStackArgs.emplace_back(&strInsn);
7391     } else {
7392         GetCurBB()->AppendInsn(strInsn);
7393     }
7394 }
7395 
7396 /* preprocess call in parmlist */
MarkParmListCall(BaseNode & expr)7397 bool AArch64CGFunc::MarkParmListCall(BaseNode &expr)
7398 {
7399     if (!CGOptions::IsPIC()) {
7400         return false;
7401     }
7402     switch (expr.GetOpCode()) {
7403         case OP_addrof: {
7404             auto &addrNode = static_cast<AddrofNode &>(expr);
7405             MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(addrNode.GetStIdx());
7406             if (symbol->IsThreadLocal()) {
7407                 return true;
7408             }
7409             break;
7410         }
7411         default: {
7412             for (auto i = 0; i < expr.GetNumOpnds(); i++) {
7413                 if (expr.Opnd(i)) {
7414                     if (MarkParmListCall(*expr.Opnd(i))) {
7415                         return true;
7416                     }
7417                 }
7418             }
7419             break;
7420         }
7421     }
7422     return false;
7423 }
7424 
7425 /*
7426    SelectParmList generates an instrunction for each of the parameters
7427    to load the parameter value into the corresponding register.
7428    We return a list of registers to the call instruction because
7429    they may be needed in the register allocation phase.
7430  */
SelectParmList(StmtNode & naryNode,ListOperand & srcOpnds,bool isCallNative)7431 void AArch64CGFunc::SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative)
7432 {
7433     size_t opndIdx = 0;
7434     // the first opnd of ICallNode is not parameter of function
7435     if (naryNode.GetOpCode() == OP_icall || naryNode.GetOpCode() == OP_icallproto || isCallNative) {
7436         opndIdx++;
7437     }
7438     auto [callee, calleeType] = GetCalleeFunction(naryNode);
7439 
7440     std::vector<ParamDesc> argsDesc;
7441     std::vector<RegMapForPhyRegCpy> regMapForTmpBB;
7442     bool hasSpecialArg = SelectParmListPreprocess(naryNode, opndIdx, argsDesc, callee);
7443     BB *curBBrecord = GetCurBB();
7444     BB *tmpBB = nullptr;
7445     if (hasSpecialArg) {
7446         tmpBB = CreateNewBB();
7447     }
7448 
7449     AArch64CallConvImpl parmLocator(GetBecommon());
7450     CCLocInfo ploc;
7451     std::vector<Insn *> insnForStackArgs;
7452 
7453     for (size_t i = 0; i < argsDesc.size(); ++i) {
7454         if (hasSpecialArg) {
7455             DEBUG_ASSERT(tmpBB, "need temp bb for lower priority args");
7456             SetCurBB(argsDesc[i].isSpecialArg ? *curBBrecord : *tmpBB);
7457         }
7458 
7459         auto *mirType = argsDesc[i].mirType;
7460 
7461         // get param opnd, for unpreCody agg, opnd must be mem opnd
7462         Operand *opnd = nullptr;
7463         auto preCopyed = argsDesc[i].preCopyed;
7464         if (preCopyed) {                     // preCopyed agg, passed by address
7465             naryNode.SetMayTailcall(false);  // has preCopyed arguments, don't do tailcall
7466             opnd = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
7467             auto &spReg = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt);
7468             SelectAdd(*opnd, spReg, CreateImmOperand(argsDesc[i].offset, k64BitSize, false), PTY_a64);
7469         } else if (mirType->GetPrimType() == PTY_agg) {
7470             opnd = SelectRhsMemOpnd(*argsDesc[i].argExpr);
7471         } else {  // base type, clac true val
7472             opnd = &LoadIntoRegister(*HandleExpr(naryNode, *argsDesc[i].argExpr), mirType->GetPrimType());
7473         }
7474         parmLocator.LocateNextParm(*mirType, ploc, (i == 0), calleeType);
7475 
7476         // skip unused args
7477         if (callee && callee->GetFuncDesc().IsArgUnused(i)) {
7478             continue;
7479         }
7480 
7481         if (ploc.reg0 != kRinvalid) {  // load to the register.
7482             if (mirType->GetPrimType() == PTY_agg && !preCopyed) {
7483                 SelectParmListSmallStruct(*mirType, ploc, *opnd, srcOpnds, argsDesc[i].isSpecialArg, regMapForTmpBB);
7484             } else if (IsInt128Ty(mirType->GetPrimType())) {
7485                 SelectParmListForInt128(*opnd, srcOpnds, ploc, argsDesc[i].isSpecialArg, regMapForTmpBB);
7486             } else {
7487                 CHECK_FATAL(ploc.reg1 == kRinvalid, "NIY");
7488                 auto &phyReg = GetOrCreatePhysicalRegisterOperand(static_cast<AArch64reg>(ploc.reg0),
7489                                                                   GetPrimTypeBitSize(ploc.primTypeOfReg0),
7490                                                                   GetRegTyFromPrimTy(ploc.primTypeOfReg0));
7491                 DEBUG_ASSERT(opnd->IsRegister(), "NIY, must be reg");
7492                 if (!DoCallerEnsureValidParm(phyReg, static_cast<RegOperand &>(*opnd), ploc.primTypeOfReg0)) {
7493                     if (argsDesc[i].isSpecialArg) {
7494                         regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(
7495                             &phyReg, ploc.primTypeOfReg0, static_cast<RegOperand *>(opnd), ploc.primTypeOfReg0));
7496                     } else {
7497                         SelectCopy(phyReg, ploc.primTypeOfReg0, *opnd, ploc.primTypeOfReg0);
7498                     }
7499                 }
7500                 srcOpnds.PushOpnd(phyReg);
7501             }
7502             continue;
7503         }
7504 
7505         // store to the memory segment for stack-passsed arguments.
7506         if (CGOptions::IsBigEndian() && ploc.memSize < static_cast<int32>(k8ByteSize)) {
7507             ploc.memOffset = ploc.memOffset + static_cast<int32>(k4ByteSize);
7508         }
7509         SelectParmListPassByStack(*mirType, *opnd, static_cast<uint32>(ploc.memOffset), preCopyed, insnForStackArgs);
7510     }
7511     // if we have stack-passed arguments, don't do tailcall
7512     parmLocator.InitCCLocInfo(ploc);
7513     if (ploc.memOffset != 0) {
7514         naryNode.SetMayTailcall(false);
7515     }
7516     if (hasSpecialArg) {
7517         DEBUG_ASSERT(tmpBB, "need temp bb for lower priority args");
7518         SetCurBB(*tmpBB);
7519         for (auto it : regMapForTmpBB) {
7520             SelectCopy(*it.destReg, it.destType, *it.srcReg, it.srcType);
7521         }
7522         curBBrecord->InsertAtEnd(*tmpBB);
7523         SetCurBB(*curBBrecord);
7524     }
7525     for (auto &strInsn : insnForStackArgs) {
7526         GetCurBB()->AppendInsn(*strInsn);
7527     }
7528 }
7529 
DoCallerEnsureValidParm(RegOperand & destOpnd,RegOperand & srcOpnd,PrimType formalPType)7530 bool AArch64CGFunc::DoCallerEnsureValidParm(RegOperand &destOpnd, RegOperand &srcOpnd, PrimType formalPType)
7531 {
7532     Insn *insn = nullptr;
7533     switch (formalPType) {
7534         case PTY_u1: {
7535             ImmOperand &lsbOpnd = CreateImmOperand(maplebe::k0BitSize, srcOpnd.GetSize(), false);
7536             ImmOperand &widthOpnd = CreateImmOperand(maplebe::k1BitSize, srcOpnd.GetSize(), false);
7537             bool is64Bit = (srcOpnd.GetSize() == maplebe::k64BitSize);
7538             insn = &GetInsnBuilder()->BuildInsn(is64Bit ? MOP_xubfxrri6i6 : MOP_wubfxrri5i5, destOpnd, srcOpnd, lsbOpnd,
7539                                                 widthOpnd);
7540             break;
7541         }
7542         case PTY_u8:
7543         case PTY_i8:
7544             insn = &GetInsnBuilder()->BuildInsn(MOP_xuxtb32, destOpnd, srcOpnd);
7545             break;
7546         case PTY_u16:
7547         case PTY_i16:
7548             insn = &GetInsnBuilder()->BuildInsn(MOP_xuxth32, destOpnd, srcOpnd);
7549             break;
7550         default:
7551             break;
7552     }
7553     if (insn != nullptr) {
7554         GetCurBB()->AppendInsn(*insn);
7555         return true;
7556     }
7557     return false;
7558 }
7559 
SelectParmListNotC(StmtNode & naryNode,ListOperand & srcOpnds)7560 void AArch64CGFunc::SelectParmListNotC(StmtNode &naryNode, ListOperand &srcOpnds)
7561 {
7562     size_t i = 0;
7563     if (naryNode.GetOpCode() == OP_icall || naryNode.GetOpCode() == OP_icallproto) {
7564         i++;
7565     }
7566 
7567     CCImpl &parmLocator = *GetOrCreateLocator(CCImpl::GetCallConvKind(naryNode));
7568     CCLocInfo ploc;
7569     std::vector<Insn *> insnForStackArgs;
7570     uint32 stackArgsCount = 0;
7571     for (uint32 pnum = 0; i < naryNode.NumOpnds(); ++i, ++pnum) {
7572         MIRType *ty = nullptr;
7573         BaseNode *argExpr = naryNode.Opnd(i);
7574         DEBUG_ASSERT(argExpr != nullptr, "argExpr should not be nullptr");
7575         PrimType primType = argExpr->GetPrimType();
7576         DEBUG_ASSERT(primType != PTY_void, "primType should not be void");
7577         /* use alloca  */
7578         ty = GlobalTables::GetTypeTable().GetTypeTable()[static_cast<uint32>(primType)];
7579         RegOperand *expRegOpnd = nullptr;
7580         Operand *opnd = HandleExpr(naryNode, *argExpr);
7581         if (!opnd->IsRegister()) {
7582             opnd = &LoadIntoRegister(*opnd, primType);
7583         }
7584         expRegOpnd = static_cast<RegOperand *>(opnd);
7585 
7586         parmLocator.LocateNextParm(*ty, ploc);
7587         PrimType destPrimType = primType;
7588         if (ploc.reg0 != kRinvalid) { /* load to the register. */
7589             CHECK_FATAL(expRegOpnd != nullptr, "null ptr check");
7590             RegOperand &parmRegOpnd = GetOrCreatePhysicalRegisterOperand(
7591                 static_cast<AArch64reg>(ploc.reg0), expRegOpnd->GetSize(), GetRegTyFromPrimTy(destPrimType));
7592             SelectCopy(parmRegOpnd, destPrimType, *expRegOpnd, primType);
7593             srcOpnds.PushOpnd(parmRegOpnd);
7594         } else { /* store to the memory segment for stack-passsed arguments. */
7595             if (CGOptions::IsBigEndian()) {
7596                 if (GetPrimTypeBitSize(primType) < k64BitSize) {
7597                     ploc.memOffset = ploc.memOffset + static_cast<int32>(k4BitSize);
7598                 }
7599             }
7600             MemOperand &actMemOpnd = CreateMemOpnd(RSP, ploc.memOffset, GetPrimTypeBitSize(primType));
7601             Insn &strInsn = GetInsnBuilder()->BuildInsn(PickStInsn(GetPrimTypeBitSize(primType), primType), *expRegOpnd,
7602                                                         actMemOpnd);
7603             actMemOpnd.SetStackArgMem(true);
7604             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel1 && stackArgsCount < kShiftAmount12) {
7605                 (void)insnForStackArgs.emplace_back(&strInsn);
7606                 stackArgsCount++;
7607             } else {
7608                 GetCurBB()->AppendInsn(strInsn);
7609             }
7610         }
7611         DEBUG_ASSERT(ploc.reg1 == 0, "SelectCall NYI");
7612     }
7613     for (auto &strInsn : insnForStackArgs) {
7614         GetCurBB()->AppendInsn(*strInsn);
7615     }
7616 }
7617 
7618 // based on call conv, choose how to prepare args
SelectParmListWrapper(StmtNode & naryNode,ListOperand & srcOpnds,bool isCallNative)7619 void AArch64CGFunc::SelectParmListWrapper(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative)
7620 {
7621     if (CCImpl::GetCallConvKind(naryNode) == kCCall) {
7622         SelectParmList(naryNode, srcOpnds, isCallNative);
7623     } else if (CCImpl::GetCallConvKind(naryNode) == kWebKitJS || CCImpl::GetCallConvKind(naryNode) == kGHC) {
7624         SelectParmListNotC(naryNode, srcOpnds);
7625     } else {
7626         CHECK_FATAL(false, "niy");
7627     }
7628 }
7629 /*
7630  * for MCC_DecRefResetPair(addrof ptr %Reg17_R5592, addrof ptr %Reg16_R6202) or
7631  * MCC_ClearLocalStackRef(addrof ptr %Reg17_R5592), the parameter (addrof ptr xxx) is converted to asm as follow:
7632  * add vreg, x29, #imm
7633  * mov R0/R1, vreg
7634  * this function is used to prepare parameters, the generated vreg is returned, and #imm is saved in offsetValue.
7635  */
SelectClearStackCallParam(const AddrofNode & expr,int64 & offsetValue)7636 Operand *AArch64CGFunc::SelectClearStackCallParam(const AddrofNode &expr, int64 &offsetValue)
7637 {
7638     CHECK_NULL_FATAL(mirModule.CurFunction());
7639     MIRSymbol *symbol = GetMirModule().CurFunction()->GetLocalOrGlobalSymbol(expr.GetStIdx());
7640     PrimType ptype = expr.GetPrimType();
7641     regno_t vRegNO = NewVReg(kRegTyInt, GetPrimTypeSize(ptype));
7642     Operand &result = CreateVirtualRegisterOperand(vRegNO);
7643     CHECK_FATAL(expr.GetFieldID() == 0, "the fieldID of parameter in clear stack reference call must be 0");
7644     if (!CGOptions::IsQuiet()) {
7645         maple::LogInfo::MapleLogger(kLlErr)
7646             << "Warning: we expect AddrOf with StImmOperand is not used for local variables";
7647     }
7648     auto *symLoc = static_cast<AArch64SymbolAlloc *>(GetMemlayout()->GetSymAllocInfo(symbol->GetStIndex()));
7649     ImmOperand *offset = nullptr;
7650     if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) {
7651         offset = &CreateImmOperand(GetBaseOffset(*symLoc), k64BitSize, false, kUnAdjustVary);
7652     } else if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsRefLocals) {
7653         auto it = immOpndsRequiringOffsetAdjustmentForRefloc.find(symLoc);
7654         if (it != immOpndsRequiringOffsetAdjustmentForRefloc.end()) {
7655             offset = (*it).second;
7656         } else {
7657             offset = &CreateImmOperand(GetBaseOffset(*symLoc), k64BitSize, false);
7658             immOpndsRequiringOffsetAdjustmentForRefloc[symLoc] = offset;
7659         }
7660     } else {
7661         CHECK_FATAL(false, "the symLoc of parameter in clear stack reference call is unreasonable");
7662     }
7663     DEBUG_ASSERT(offset != nullptr, "offset should not be nullptr");
7664     offsetValue = offset->GetValue();
7665     SelectAdd(result, *GetBaseReg(*symLoc), *offset, PTY_u64);
7666     if (GetCG()->GenerateVerboseCG()) {
7667         /* Add a comment */
7668         Insn *insn = GetCurBB()->GetLastInsn();
7669         std::string comm = "local/formal var: ";
7670         comm += symbol->GetName();
7671         insn->SetComment(comm);
7672     }
7673     return &result;
7674 }
7675 
7676 /* select paramters for MCC_DecRefResetPair and MCC_ClearLocalStackRef function */
SelectClearStackCallParmList(const StmtNode & naryNode,ListOperand & srcOpnds,std::vector<int64> & stackPostion)7677 void AArch64CGFunc::SelectClearStackCallParmList(const StmtNode &naryNode, ListOperand &srcOpnds,
7678                                                  std::vector<int64> &stackPostion)
7679 {
7680     CHECK_FATAL(false, "should not go here");
7681     AArch64CallConvImpl parmLocator(GetBecommon());
7682     CCLocInfo ploc;
7683     for (size_t i = 0; i < naryNode.NumOpnds(); ++i) {
7684         MIRType *ty = nullptr;
7685         BaseNode *argExpr = naryNode.Opnd(i);
7686         PrimType primType = argExpr->GetPrimType();
7687         DEBUG_ASSERT(primType != PTY_void, "primType check");
7688         /* use alloc */
7689         CHECK_FATAL(primType != PTY_agg, "the type of argument is unreasonable");
7690         ty = GlobalTables::GetTypeTable().GetTypeTable()[static_cast<uint32>(primType)];
7691         CHECK_FATAL(argExpr->GetOpCode() == OP_addrof, "the argument of clear stack call is unreasonable");
7692         auto *expr = static_cast<AddrofNode *>(argExpr);
7693         int64 offsetValue = 0;
7694         Operand *opnd = SelectClearStackCallParam(*expr, offsetValue);
7695         stackPostion.emplace_back(offsetValue);
7696         auto *expRegOpnd = static_cast<RegOperand *>(opnd);
7697         parmLocator.LocateNextParm(*ty, ploc);
7698         CHECK_FATAL(ploc.reg0 != 0, "the parameter of ClearStackCall must be passed by register");
7699         CHECK_FATAL(expRegOpnd != nullptr, "null ptr check");
7700         RegOperand &parmRegOpnd = GetOrCreatePhysicalRegisterOperand(
7701             static_cast<AArch64reg>(ploc.reg0), expRegOpnd->GetSize(), GetRegTyFromPrimTy(primType));
7702         SelectCopy(parmRegOpnd, primType, *expRegOpnd, primType);
7703         srcOpnds.PushOpnd(parmRegOpnd);
7704         DEBUG_ASSERT(ploc.reg1 == 0, "SelectCall NYI");
7705     }
7706 }
7707 
7708 /*
7709  * intrinsify Unsafe.getAndAddInt and Unsafe.getAndAddLong
7710  * generate an intrinsic instruction instead of a function call
7711  * intrinsic_get_add_int w0, xt, ws, ws, x1, x2, w3, label
7712  */
IntrinsifyGetAndAddInt(ListOperand & srcOpnds,PrimType pty)7713 void AArch64CGFunc::IntrinsifyGetAndAddInt(ListOperand &srcOpnds, PrimType pty)
7714 {
7715     MapleList<RegOperand *> &opnds = srcOpnds.GetOperands();
7716     /* Unsafe.getAndAddInt has more than 4 parameters */
7717     DEBUG_ASSERT(opnds.size() >= 4, "ensure the operands number");
7718     auto iter = opnds.begin();
7719     RegOperand *objOpnd = *(++iter);
7720     RegOperand *offOpnd = *(++iter);
7721     RegOperand *deltaOpnd = *(++iter);
7722     auto &retVal = static_cast<RegOperand &>(GetTargetRetOperand(pty, -1));
7723     LabelIdx labIdx = CreateLabel();
7724     LabelOperand &targetOpnd = GetOrCreateLabelOperand(labIdx);
7725     RegOperand &tempOpnd0 = CreateRegisterOperandOfType(PTY_i64);
7726     RegOperand &tempOpnd1 = CreateRegisterOperandOfType(pty);
7727     RegOperand &tempOpnd2 = CreateRegisterOperandOfType(PTY_i32);
7728     MOperator mOp = (pty == PTY_i64) ? MOP_get_and_addL : MOP_get_and_addI;
7729     std::vector<Operand *> intrnOpnds;
7730     intrnOpnds.emplace_back(&retVal);
7731     intrnOpnds.emplace_back(&tempOpnd0);
7732     intrnOpnds.emplace_back(&tempOpnd1);
7733     intrnOpnds.emplace_back(&tempOpnd2);
7734     intrnOpnds.emplace_back(objOpnd);
7735     intrnOpnds.emplace_back(offOpnd);
7736     intrnOpnds.emplace_back(deltaOpnd);
7737     intrnOpnds.emplace_back(&targetOpnd);
7738     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, intrnOpnds));
7739 }
7740 
7741 /*
7742  * intrinsify Unsafe.getAndSetInt and Unsafe.getAndSetLong
7743  * generate an intrinsic instruction instead of a function call
7744  */
IntrinsifyGetAndSetInt(ListOperand & srcOpnds,PrimType pty)7745 void AArch64CGFunc::IntrinsifyGetAndSetInt(ListOperand &srcOpnds, PrimType pty)
7746 {
7747     MapleList<RegOperand *> &opnds = srcOpnds.GetOperands();
7748     /* Unsafe.getAndSetInt has 4 parameters */
7749     DEBUG_ASSERT(opnds.size() == 4, "ensure the operands number");
7750     auto iter = opnds.begin();
7751     RegOperand *objOpnd = *(++iter);
7752     RegOperand *offOpnd = *(++iter);
7753     RegOperand *newValueOpnd = *(++iter);
7754     auto &retVal = static_cast<RegOperand &>(GetTargetRetOperand(pty, -1));
7755     LabelIdx labIdx = CreateLabel();
7756     LabelOperand &targetOpnd = GetOrCreateLabelOperand(labIdx);
7757     RegOperand &tempOpnd0 = CreateRegisterOperandOfType(PTY_i64);
7758     RegOperand &tempOpnd1 = CreateRegisterOperandOfType(PTY_i32);
7759 
7760     MOperator mOp = (pty == PTY_i64) ? MOP_get_and_setL : MOP_get_and_setI;
7761     std::vector<Operand *> intrnOpnds;
7762     intrnOpnds.emplace_back(&retVal);
7763     intrnOpnds.emplace_back(&tempOpnd0);
7764     intrnOpnds.emplace_back(&tempOpnd1);
7765     intrnOpnds.emplace_back(objOpnd);
7766     intrnOpnds.emplace_back(offOpnd);
7767     intrnOpnds.emplace_back(newValueOpnd);
7768     intrnOpnds.emplace_back(&targetOpnd);
7769     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, intrnOpnds));
7770 }
7771 
7772 /*
7773  * intrinsify Unsafe.compareAndSwapInt and Unsafe.compareAndSwapLong
7774  * generate an intrinsic instruction instead of a function call
7775  */
IntrinsifyCompareAndSwapInt(ListOperand & srcOpnds,PrimType pty)7776 void AArch64CGFunc::IntrinsifyCompareAndSwapInt(ListOperand &srcOpnds, PrimType pty)
7777 {
7778     MapleList<RegOperand *> &opnds = srcOpnds.GetOperands();
7779     /* Unsafe.compareAndSwapInt has more than 5 parameters */
7780     DEBUG_ASSERT(opnds.size() >= 5, "ensure the operands number");
7781     auto iter = opnds.begin();
7782     RegOperand *objOpnd = *(++iter);
7783     RegOperand *offOpnd = *(++iter);
7784     RegOperand *expectedValueOpnd = *(++iter);
7785     RegOperand *newValueOpnd = *(++iter);
7786     auto &retVal = static_cast<RegOperand &>(GetTargetRetOperand(PTY_i64, -1));
7787     RegOperand &tempOpnd0 = CreateRegisterOperandOfType(PTY_i64);
7788     RegOperand &tempOpnd1 = CreateRegisterOperandOfType(pty);
7789     LabelIdx labIdx1 = CreateLabel();
7790     LabelOperand &label1Opnd = GetOrCreateLabelOperand(labIdx1);
7791     LabelIdx labIdx2 = CreateLabel();
7792     LabelOperand &label2Opnd = GetOrCreateLabelOperand(labIdx2);
7793     MOperator mOp = (pty == PTY_i32) ? MOP_compare_and_swapI : MOP_compare_and_swapL;
7794     std::vector<Operand *> intrnOpnds;
7795     intrnOpnds.emplace_back(&retVal);
7796     intrnOpnds.emplace_back(&tempOpnd0);
7797     intrnOpnds.emplace_back(&tempOpnd1);
7798     intrnOpnds.emplace_back(objOpnd);
7799     intrnOpnds.emplace_back(offOpnd);
7800     intrnOpnds.emplace_back(expectedValueOpnd);
7801     intrnOpnds.emplace_back(newValueOpnd);
7802     intrnOpnds.emplace_back(&label1Opnd);
7803     intrnOpnds.emplace_back(&label2Opnd);
7804     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, intrnOpnds));
7805 }
7806 
7807 /*
7808  * the lowest bit of count field is used to indicate whether or not the string is compressed
7809  * if the string is not compressed, jump to jumpLabIdx
7810  */
CheckStringIsCompressed(BB & bb,RegOperand & str,int32 countOffset,PrimType countPty,LabelIdx jumpLabIdx)7811 RegOperand *AArch64CGFunc::CheckStringIsCompressed(BB &bb, RegOperand &str, int32 countOffset, PrimType countPty,
7812                                                    LabelIdx jumpLabIdx)
7813 {
7814     MemOperand &memOpnd = CreateMemOpnd(str, countOffset, str.GetSize());
7815     uint32 bitSize = GetPrimTypeBitSize(countPty);
7816     MOperator loadOp = PickLdInsn(bitSize, countPty);
7817     RegOperand &countOpnd = CreateRegisterOperandOfType(countPty);
7818     bb.AppendInsn(GetInsnBuilder()->BuildInsn(loadOp, countOpnd, memOpnd));
7819     ImmOperand &immValueOne = CreateImmOperand(countPty, 1);
7820     RegOperand &countLowestBitOpnd = CreateRegisterOperandOfType(countPty);
7821     MOperator andOp = bitSize == k64BitSize ? MOP_xandrri13 : MOP_wandrri12;
7822     bb.AppendInsn(GetInsnBuilder()->BuildInsn(andOp, countLowestBitOpnd, countOpnd, immValueOne));
7823     RegOperand &wzr = GetZeroOpnd(bitSize);
7824     MOperator cmpOp = (bitSize == k64BitSize) ? MOP_xcmprr : MOP_wcmprr;
7825     Operand &rflag = GetOrCreateRflag();
7826     bb.AppendInsn(GetInsnBuilder()->BuildInsn(cmpOp, rflag, wzr, countLowestBitOpnd));
7827     bb.AppendInsn(GetInsnBuilder()->BuildInsn(MOP_beq, rflag, GetOrCreateLabelOperand(jumpLabIdx)));
7828     bb.SetKind(BB::kBBIf);
7829     return &countOpnd;
7830 }
7831 
7832 /*
7833  * count field stores the length shifted one bit to the left
7834  * if the length is less than eight, jump to jumpLabIdx
7835  */
CheckStringLengthLessThanEight(BB & bb,RegOperand & countOpnd,PrimType countPty,LabelIdx jumpLabIdx)7836 RegOperand *AArch64CGFunc::CheckStringLengthLessThanEight(BB &bb, RegOperand &countOpnd, PrimType countPty,
7837                                                           LabelIdx jumpLabIdx)
7838 {
7839     RegOperand &lengthOpnd = CreateRegisterOperandOfType(countPty);
7840     uint32 bitSize = GetPrimTypeBitSize(countPty);
7841     MOperator lsrOp = (bitSize == k64BitSize) ? MOP_xlsrrri6 : MOP_wlsrrri5;
7842     ImmOperand &immValueOne = CreateImmOperand(countPty, 1);
7843     bb.AppendInsn(GetInsnBuilder()->BuildInsn(lsrOp, lengthOpnd, countOpnd, immValueOne));
7844     constexpr int kConstIntEight = 8;
7845     ImmOperand &immValueEight = CreateImmOperand(countPty, kConstIntEight);
7846     MOperator cmpImmOp = (bitSize == k64BitSize) ? MOP_xcmpri : MOP_wcmpri;
7847     Operand &rflag = GetOrCreateRflag();
7848     bb.AppendInsn(GetInsnBuilder()->BuildInsn(cmpImmOp, rflag, lengthOpnd, immValueEight));
7849     bb.AppendInsn(GetInsnBuilder()->BuildInsn(MOP_blt, rflag, GetOrCreateLabelOperand(jumpLabIdx)));
7850     bb.SetKind(BB::kBBIf);
7851     return &lengthOpnd;
7852 }
7853 
GenerateIntrnInsnForStrIndexOf(BB & bb,RegOperand & srcString,RegOperand & patternString,RegOperand & srcCountOpnd,RegOperand & patternLengthOpnd,PrimType countPty,LabelIdx jumpLabIdx)7854 void AArch64CGFunc::GenerateIntrnInsnForStrIndexOf(BB &bb, RegOperand &srcString, RegOperand &patternString,
7855                                                    RegOperand &srcCountOpnd, RegOperand &patternLengthOpnd,
7856                                                    PrimType countPty, LabelIdx jumpLabIdx)
7857 {
7858     RegOperand &srcLengthOpnd = CreateRegisterOperandOfType(countPty);
7859     ImmOperand &immValueOne = CreateImmOperand(countPty, 1);
7860     uint32 bitSize = GetPrimTypeBitSize(countPty);
7861     MOperator lsrOp = (bitSize == k64BitSize) ? MOP_xlsrrri6 : MOP_wlsrrri5;
7862     bb.AppendInsn(GetInsnBuilder()->BuildInsn(lsrOp, srcLengthOpnd, srcCountOpnd, immValueOne));
7863 #ifdef USE_32BIT_REF
7864     const int64 stringBaseObjSize = 16; /* shadow(4)+monitor(4)+count(4)+hash(4) */
7865 #else
7866     const int64 stringBaseObjSize = 20; /* shadow(8)+monitor(4)+count(4)+hash(4) */
7867 #endif /* USE_32BIT_REF */
7868     PrimType pty = (srcString.GetSize() == k64BitSize) ? PTY_i64 : PTY_i32;
7869     ImmOperand &immStringBaseOffset = CreateImmOperand(pty, stringBaseObjSize);
7870     MOperator addOp = (pty == PTY_i64) ? MOP_xaddrri12 : MOP_waddrri12;
7871     RegOperand &srcStringBaseOpnd = CreateRegisterOperandOfType(pty);
7872     bb.AppendInsn(GetInsnBuilder()->BuildInsn(addOp, srcStringBaseOpnd, srcString, immStringBaseOffset));
7873     RegOperand &patternStringBaseOpnd = CreateRegisterOperandOfType(pty);
7874     bb.AppendInsn(GetInsnBuilder()->BuildInsn(addOp, patternStringBaseOpnd, patternString, immStringBaseOffset));
7875     auto &retVal = static_cast<RegOperand &>(GetTargetRetOperand(PTY_i32, -1));
7876     std::vector<Operand *> intrnOpnds;
7877     intrnOpnds.emplace_back(&retVal);
7878     intrnOpnds.emplace_back(&srcStringBaseOpnd);
7879     intrnOpnds.emplace_back(&srcLengthOpnd);
7880     intrnOpnds.emplace_back(&patternStringBaseOpnd);
7881     intrnOpnds.emplace_back(&patternLengthOpnd);
7882     const uint32 tmpRegOperandNum = 6;
7883     for (uint32 i = 0; i < tmpRegOperandNum - 1; ++i) {
7884         RegOperand &tmpOpnd = CreateRegisterOperandOfType(PTY_i64);
7885         intrnOpnds.emplace_back(&tmpOpnd);
7886     }
7887     intrnOpnds.emplace_back(&CreateRegisterOperandOfType(PTY_i32));
7888     const uint32 labelNum = 7;
7889     for (uint32 i = 0; i < labelNum; ++i) {
7890         LabelIdx labIdx = CreateLabel();
7891         LabelOperand &labelOpnd = GetOrCreateLabelOperand(labIdx);
7892         intrnOpnds.emplace_back(&labelOpnd);
7893     }
7894     bb.AppendInsn(GetInsnBuilder()->BuildInsn(MOP_string_indexof, intrnOpnds));
7895     bb.AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xuncond, GetOrCreateLabelOperand(jumpLabIdx)));
7896     bb.SetKind(BB::kBBGoto);
7897 }
7898 
SelectCall(CallNode & callNode)7899 void AArch64CGFunc::SelectCall(CallNode &callNode)
7900 {
7901     MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx());
7902     MIRSymbol *fsym = GetFunction().GetLocalOrGlobalSymbol(fn->GetStIdx(), false);
7903     MIRType *retType = fn->GetReturnType();
7904 
7905     if (GetCG()->GenerateVerboseCG()) {
7906         const std::string &comment = fsym->GetName();
7907         GetCurBB()->AppendInsn(CreateCommentInsn(comment));
7908     }
7909 
7910     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
7911     if (GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) {
7912         SetLmbcCallReturnType(nullptr);
7913         if (fn->IsFirstArgReturn()) {
7914             MIRPtrType *ptrTy = static_cast<MIRPtrType *>(
7915                 GlobalTables::GetTypeTable().GetTypeFromTyIdx(fn->GetFormalDefVec()[0].formalTyIdx));
7916             MIRType *sTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrTy->GetPointedTyIdx());
7917             SetLmbcCallReturnType(sTy);
7918         } else {
7919             MIRType *ty = fn->GetReturnType();
7920             SetLmbcCallReturnType(ty);
7921         }
7922     }
7923 
7924     SelectParmListWrapper(callNode, *srcOpnds, false);
7925 
7926     Insn &callInsn = AppendCall(*fsym, *srcOpnds);
7927     GetCurBB()->SetHasCall();
7928     if (retType != nullptr) {
7929         callInsn.SetRetSize(static_cast<uint32>(retType->GetSize()));
7930         callInsn.SetIsCallReturnUnsigned(IsUnsignedInteger(retType->GetPrimType()));
7931     }
7932     const auto &deoptBundleInfo = callNode.GetDeoptBundleInfo();
7933     for (const auto &elem : deoptBundleInfo) {
7934         auto valueKind = elem.second.GetMapleValueKind();
7935         if (valueKind == MapleValue::kPregKind) {
7936             auto *opnd = GetOpndFromPregIdx(elem.second.GetPregIdx());
7937             CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
7938             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
7939         } else if (valueKind == MapleValue::kConstKind) {
7940             auto *opnd = SelectIntConst(static_cast<const MIRIntConst &>(elem.second.GetConstValue()), callNode);
7941             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
7942         } else {
7943             CHECK_FATAL(false, "not supported currently");
7944         }
7945     }
7946     AppendStackMapInsn(callInsn);
7947 
7948     /* check if this call use stack slot to return */
7949     if (fn->IsFirstArgReturn()) {
7950         SetStackProtectInfo(kRetureStackSlot);
7951     }
7952 
7953     GetFunction().SetHasCall();
7954     if (GetMirModule().IsCModule()) { /* do not mark abort BB in C at present */
7955         if (fsym->GetName() == "__builtin_unreachable") {
7956             GetCurBB()->ClearInsns();
7957             GetCurBB()->SetUnreachable(true);
7958         }
7959         return;
7960     }
7961 }
7962 
SelectIcall(IcallNode & icallNode)7963 void AArch64CGFunc::SelectIcall(IcallNode &icallNode)
7964 {
7965     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
7966     SelectParmListWrapper(icallNode, *srcOpnds, false);
7967 
7968     Operand *srcOpnd = HandleExpr(icallNode, *icallNode.GetNopndAt(0));
7969     Operand *fptrOpnd = srcOpnd;
7970     if (fptrOpnd->GetKind() != Operand::kOpdRegister) {
7971         PrimType ty = icallNode.Opnd(0)->GetPrimType();
7972         fptrOpnd = &SelectCopy(*srcOpnd, ty, ty);
7973     }
7974     DEBUG_ASSERT(fptrOpnd->IsRegister(), "SelectIcall: function pointer not RegOperand");
7975     RegOperand *regOpnd = static_cast<RegOperand *>(fptrOpnd);
7976     Insn &callInsn = GetInsnBuilder()->BuildInsn(MOP_xblr, *regOpnd, *srcOpnds);
7977 
7978     MIRType *retType = icallNode.GetCallReturnType();
7979     if (retType != nullptr) {
7980         callInsn.SetRetSize(static_cast<uint32>(retType->GetSize()));
7981         callInsn.SetIsCallReturnUnsigned(IsUnsignedInteger(retType->GetPrimType()));
7982     }
7983 
7984     /* check if this icall use stack slot to return */
7985     CallReturnVector *p2nrets = &icallNode.GetReturnVec();
7986     if (p2nrets->size() == k1ByteSize) {
7987         StIdx stIdx = (*p2nrets)[0].first;
7988         CHECK_NULL_FATAL(mirModule.CurFunction());
7989         MIRSymbol *sym = GetBecommon().GetMIRModule().CurFunction()->GetSymTab()->GetSymbolFromStIdx(stIdx.Idx());
7990         if (sym != nullptr && (GetBecommon().GetTypeSize(sym->GetTyIdx().GetIdx()) > k16ByteSize)) {
7991             SetStackProtectInfo(kRetureStackSlot);
7992         }
7993     }
7994 
7995     GetCurBB()->AppendInsn(callInsn);
7996     GetCurBB()->SetHasCall();
7997     DEBUG_ASSERT(GetCurBB()->GetLastMachineInsn()->IsCall(), "lastInsn should be a call");
7998     GetFunction().SetHasCall();
7999     const auto &deoptBundleInfo = icallNode.GetDeoptBundleInfo();
8000     for (const auto &elem : deoptBundleInfo) {
8001         auto valueKind = elem.second.GetMapleValueKind();
8002         if (valueKind == MapleValue::kPregKind) {
8003             auto *opnd = GetOpndFromPregIdx(elem.second.GetPregIdx());
8004             CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
8005             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
8006         } else if (valueKind == MapleValue::kConstKind) {
8007             auto *opnd = SelectIntConst(static_cast<const MIRIntConst &>(elem.second.GetConstValue()), icallNode);
8008             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
8009         } else {
8010             CHECK_FATAL(false, "not supported currently");
8011         }
8012     }
8013     AppendStackMapInsn(callInsn);
8014 }
8015 
HandleCatch()8016 void AArch64CGFunc::HandleCatch()
8017 {
8018     if (Globals::GetInstance()->GetOptimLevel() >= CGOptions::kLevel1) {
8019         regno_t regNO = uCatch.regNOCatch;
8020         RegOperand &vregOpnd = GetOrCreateVirtualRegisterOperand(regNO);
8021         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(
8022             MOP_xmovrr, vregOpnd, GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, kRegTyInt)));
8023     } else {
8024         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(
8025             PickStInsn(uCatch.opndCatch->GetSize(), PTY_a64),
8026             GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, kRegTyInt), *uCatch.opndCatch));
8027     }
8028 }
8029 
SelectMembar(StmtNode & membar)8030 void AArch64CGFunc::SelectMembar(StmtNode &membar)
8031 {
8032     switch (membar.GetOpCode()) {
8033         case OP_membaracquire:
8034             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ishld, AArch64CG::kMd[MOP_dmb_ishld]));
8035             break;
8036         case OP_membarrelease:
8037         case OP_membarstoreload:
8038             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ish, AArch64CG::kMd[MOP_dmb_ish]));
8039             break;
8040         case OP_membarstorestore:
8041             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ishst, AArch64CG::kMd[MOP_dmb_ishst]));
8042             break;
8043         default:
8044             DEBUG_ASSERT(false, "NYI");
8045             break;
8046     }
8047 }
8048 
SelectComment(CommentNode & comment)8049 void AArch64CGFunc::SelectComment(CommentNode &comment)
8050 {
8051     GetCurBB()->AppendInsn(CreateCommentInsn(comment.GetComment()));
8052 }
8053 
SelectReturn(Operand * opnd0)8054 void AArch64CGFunc::SelectReturn(Operand *opnd0)
8055 {
8056     bool is64x1vec = GetFunction().GetAttr(FUNCATTR_oneelem_simd) ? true : false;
8057     MIRType *floatType = GlobalTables::GetTypeTable().GetDouble();
8058     MIRType *retTyp = is64x1vec ? floatType : GetFunction().GetReturnType();
8059     CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind());
8060     CCLocInfo retMech;
8061     retLocator.LocateRetVal(*retTyp, retMech);
8062     if ((retMech.GetRegCount() > 0) && (opnd0 != nullptr)) {
8063         RegType regTyp = is64x1vec ? kRegTyFloat : GetRegTyFromPrimTy(retMech.GetPrimTypeOfReg0());
8064         PrimType oriPrimType = is64x1vec ? GetFunction().GetReturnType()->GetPrimType() : retMech.GetPrimTypeOfReg0();
8065         AArch64reg retReg = static_cast<AArch64reg>(retMech.GetReg0());
8066         if (opnd0->IsRegister()) {
8067             RegOperand *regOpnd = static_cast<RegOperand *>(opnd0);
8068             if (regOpnd->GetRegisterNumber() != retMech.GetReg0()) {
8069                 RegOperand &retOpnd = GetOrCreatePhysicalRegisterOperand(retReg, regOpnd->GetSize(), regTyp);
8070                 SelectCopy(retOpnd, retMech.GetPrimTypeOfReg0(), *regOpnd, oriPrimType);
8071             }
8072         } else if (opnd0->IsMemoryAccessOperand()) {
8073             auto *memopnd = static_cast<MemOperand *>(opnd0);
8074             RegOperand &retOpnd =
8075                 GetOrCreatePhysicalRegisterOperand(retReg, GetPrimTypeBitSize(retMech.GetPrimTypeOfReg0()), regTyp);
8076             MOperator mOp = PickLdInsn(memopnd->GetSize(), retMech.GetPrimTypeOfReg0());
8077             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, retOpnd, *memopnd));
8078         } else if (opnd0->IsConstImmediate()) {
8079             ImmOperand *immOpnd = static_cast<ImmOperand *>(opnd0);
8080             if (!is64x1vec) {
8081                 RegOperand &retOpnd =
8082                     GetOrCreatePhysicalRegisterOperand(retReg, GetPrimTypeBitSize(retMech.GetPrimTypeOfReg0()),
8083                                                        GetRegTyFromPrimTy(retMech.GetPrimTypeOfReg0()));
8084                 SelectCopy(retOpnd, retMech.GetPrimTypeOfReg0(), *immOpnd, retMech.GetPrimTypeOfReg0());
8085             } else {
8086                 PrimType rType = GetFunction().GetReturnType()->GetPrimType();
8087                 RegOperand *reg = &CreateRegisterOperandOfType(rType);
8088                 SelectCopy(*reg, rType, *immOpnd, rType);
8089                 RegOperand &retOpnd = GetOrCreatePhysicalRegisterOperand(retReg, GetPrimTypeBitSize(PTY_f64),
8090                                                                          GetRegTyFromPrimTy(PTY_f64));
8091                 Insn &insn = GetInsnBuilder()->BuildInsn(MOP_xvmovdr, retOpnd, *reg);
8092                 GetCurBB()->AppendInsn(insn);
8093             }
8094         } else {
8095             CHECK_FATAL(false, "nyi");
8096         }
8097     }
8098     GetExitBBsVec().emplace_back(GetCurBB());
8099 }
8100 
GetOrCreateSpecialRegisterOperand(PregIdx sregIdx,PrimType primType)8101 RegOperand &AArch64CGFunc::GetOrCreateSpecialRegisterOperand(PregIdx sregIdx, PrimType primType)
8102 {
8103     switch (sregIdx) {
8104         case kSregSp:
8105             return GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt);
8106         case kSregFp:
8107             return GetOrCreatePhysicalRegisterOperand(RFP, k64BitSize, kRegTyInt);
8108         case kSregGp: {
8109             MIRSymbol *sym = GetCG()->GetGP();
8110             if (sym == nullptr) {
8111                 sym = GetFunction().GetSymTab()->CreateSymbol(kScopeLocal);
8112                 std::string strBuf("__file__local__GP");
8113                 sym->SetNameStrIdx(GetMirModule().GetMIRBuilder()->GetOrCreateStringIndex(strBuf));
8114                 GetCG()->SetGP(sym);
8115             }
8116             RegOperand &result = GetOrCreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
8117             SelectAddrof(result, CreateStImmOperand(*sym, 0, 0));
8118             return result;
8119         }
8120         case kSregThrownval: { /* uses x0 == R0 */
8121             DEBUG_ASSERT(uCatch.regNOCatch > 0, "regNOCatch should greater than 0.");
8122             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
8123                 RegOperand &regOpnd = GetOrCreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize));
8124                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(uCatch.opndCatch->GetSize(), PTY_a64),
8125                                                                    regOpnd, *uCatch.opndCatch));
8126                 return regOpnd;
8127             } else {
8128                 return GetOrCreateVirtualRegisterOperand(uCatch.regNOCatch);
8129             }
8130         }
8131         case kSregMethodhdl:
8132             if (methodHandleVreg == regno_t(-1)) {
8133                 methodHandleVreg = NewVReg(kRegTyInt, k8BitSize);
8134             }
8135             return GetOrCreateVirtualRegisterOperand(methodHandleVreg);
8136         default:
8137             break;
8138     }
8139 
8140     // process the 128-bit return value
8141     if (IsInt128Ty(primType)) {
8142         Operand &low = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_u64));
8143         Operand &high = GetOrCreatePhysicalRegisterOperand(R1, k64BitSize, GetRegTyFromPrimTy(PTY_u64));
8144         return CombineInt128({low, high});
8145     }
8146 
8147     bool useFpReg = !IsPrimitiveInteger(primType) || IsPrimitiveVectorFloat(primType);
8148     AArch64reg pReg = RLAST_INT_REG;
8149     switch (sregIdx) {
8150         case kSregRetval0:
8151             pReg = useFpReg ? V0 : R0;
8152             break;
8153         case kSregRetval1:
8154             pReg = useFpReg ? V1 : R1;
8155             break;
8156         case kSregRetval2:
8157             pReg = V2;
8158             break;
8159         case kSregRetval3:
8160             pReg = V3;
8161             break;
8162         default:
8163             DEBUG_ASSERT(false, "Special pseudo registers NYI");
8164             break;
8165     }
8166     uint32 bitSize = GetPrimTypeBitSize(primType);
8167     bitSize = bitSize <= k32BitSize ? k32BitSize : bitSize;
8168     auto &phyOpnd = GetOrCreatePhysicalRegisterOperand(pReg, bitSize, GetRegTyFromPrimTy(primType));
8169     return SelectCopy(phyOpnd, primType, primType);  // most opt only deal vreg, so return a vreg
8170 }
8171 
GetOrCreatePhysicalRegisterOperand(std::string & asmAttr)8172 RegOperand &AArch64CGFunc::GetOrCreatePhysicalRegisterOperand(std::string &asmAttr)
8173 {
8174     DEBUG_ASSERT(!asmAttr.empty(), "Get inline asm string failed in GetOrCreatePhysicalRegisterOperand");
8175     RegType rKind = kRegTyUndef;
8176     uint32 rSize = 0;
8177     /* Get Register Type and Size */
8178     switch (asmAttr[0]) {
8179         case 'x': {
8180             rKind = kRegTyInt;
8181             rSize = k64BitSize;
8182             break;
8183         }
8184         case 'w': {
8185             rKind = kRegTyInt;
8186             rSize = k32BitSize;
8187             break;
8188         }
8189         default: {
8190             LogInfo::MapleLogger() << "Unsupport asm string : " << asmAttr << "\n";
8191             CHECK_FATAL(false, "Have not support this kind of register ");
8192         }
8193     }
8194     AArch64reg rNO = kRinvalid;
8195     /* Get Register Number */
8196     uint32 regNumPos = 1;
8197     char numberChar = asmAttr[regNumPos++];
8198     if (numberChar >= '0' && numberChar <= '9') {
8199         uint32 val = static_cast<uint32>(numberChar - '0');
8200         if (regNumPos < asmAttr.length()) {
8201             char numberCharSecond = asmAttr[regNumPos++];
8202             DEBUG_ASSERT(regNumPos == asmAttr.length(), "Invalid asm attribute");
8203             if (numberCharSecond >= '0' && numberCharSecond <= '9') {
8204                 val = val * kDecimalMax + static_cast<uint32>((numberCharSecond - '0'));
8205             }
8206         }
8207         rNO = static_cast<AArch64reg>(static_cast<uint32>(R0) + val);
8208         if (val > (kAsmInputRegPrefixOpnd + 1)) {
8209             LogInfo::MapleLogger() << "Unsupport asm string : " << asmAttr << "\n";
8210             CHECK_FATAL(false, "have not support this kind of register ");
8211         }
8212     } else if (numberChar == 0) {
8213         return CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
8214     } else {
8215         CHECK_FATAL(false, "Unexpect input in GetOrCreatePhysicalRegisterOperand");
8216     }
8217     return GetOrCreatePhysicalRegisterOperand(rNO, rSize, rKind);
8218 }
8219 
GetOrCreatePhysicalRegisterOperand(AArch64reg regNO,uint32 size,RegType kind,uint32 flag)8220 RegOperand &AArch64CGFunc::GetOrCreatePhysicalRegisterOperand(AArch64reg regNO, uint32 size, RegType kind, uint32 flag)
8221 {
8222     uint64 aarch64PhyRegIdx = regNO;
8223     DEBUG_ASSERT(flag == 0, "Do not expect flag here");
8224     if (size <= k32BitSize) {
8225         size = k32BitSize;
8226         aarch64PhyRegIdx = aarch64PhyRegIdx << 1;
8227     } else if (size <= k64BitSize) {
8228         size = k64BitSize;
8229         aarch64PhyRegIdx = (aarch64PhyRegIdx << 1) + 1;
8230     } else {
8231         size = (size == k128BitSize) ? k128BitSize : k64BitSize;
8232         aarch64PhyRegIdx = aarch64PhyRegIdx << k4BitShift;
8233     }
8234     RegOperand *phyRegOpnd = nullptr;
8235     auto phyRegIt = phyRegOperandTable.find(aarch64PhyRegIdx);
8236     if (phyRegIt != phyRegOperandTable.end()) {
8237         phyRegOpnd = phyRegOperandTable[aarch64PhyRegIdx];
8238     } else {
8239         phyRegOpnd = memPool->New<RegOperand>(regNO, size, kind, flag);
8240         phyRegOperandTable.emplace(aarch64PhyRegIdx, phyRegOpnd);
8241     }
8242     return *phyRegOpnd;
8243 }
8244 
GetLabelOperand(LabelIdx labIdx) const8245 const LabelOperand *AArch64CGFunc::GetLabelOperand(LabelIdx labIdx) const
8246 {
8247     const MapleUnorderedMap<LabelIdx, LabelOperand *>::const_iterator it = hashLabelOpndTable.find(labIdx);
8248     if (it != hashLabelOpndTable.end()) {
8249         return it->second;
8250     }
8251     return nullptr;
8252 }
8253 
GetOrCreateLabelOperand(LabelIdx labIdx)8254 LabelOperand &AArch64CGFunc::GetOrCreateLabelOperand(LabelIdx labIdx)
8255 {
8256     MapleUnorderedMap<LabelIdx, LabelOperand *>::iterator it = hashLabelOpndTable.find(labIdx);
8257     if (it != hashLabelOpndTable.end()) {
8258         return *(it->second);
8259     }
8260     LabelOperand *res = memPool->New<LabelOperand>(GetShortFuncName().c_str(), labIdx, *memPool);
8261     hashLabelOpndTable[labIdx] = res;
8262     return *res;
8263 }
8264 
GetOrCreateLabelOperand(BB & bb)8265 LabelOperand &AArch64CGFunc::GetOrCreateLabelOperand(BB &bb)
8266 {
8267     LabelIdx labelIdx = bb.GetLabIdx();
8268     if (labelIdx == MIRLabelTable::GetDummyLabel()) {
8269         labelIdx = CreateLabel();
8270         bb.AddLabel(labelIdx);
8271         SetLab2BBMap(labelIdx, bb);
8272     }
8273     return GetOrCreateLabelOperand(labelIdx);
8274 }
8275 
GetAggCopySize(uint32 offset1,uint32 offset2,uint32 alignment) const8276 uint32 AArch64CGFunc::GetAggCopySize(uint32 offset1, uint32 offset2, uint32 alignment) const
8277 {
8278     /* Generating a larger sized mem op than alignment if allowed by aggregate starting address */
8279     uint32 offsetAlign1 = (offset1 == 0) ? k8ByteSize : offset1;
8280     uint32 offsetAlign2 = (offset2 == 0) ? k8ByteSize : offset2;
8281     uint32 alignOffset =
8282         1U << (std::min(__builtin_ffs(static_cast<int>(offsetAlign1)), __builtin_ffs(static_cast<int>(offsetAlign2))) -
8283                1);
8284     if (alignOffset == k8ByteSize || alignOffset == k4ByteSize || alignOffset == k2ByteSize) {
8285         return alignOffset;
8286     } else if (alignOffset > k8ByteSize) {
8287         return k8ByteSize;
8288     } else {
8289         return alignment;
8290     }
8291 }
8292 
GetOrCreateOfstOpnd(uint64 offset,uint32 size)8293 OfstOperand &AArch64CGFunc::GetOrCreateOfstOpnd(uint64 offset, uint32 size)
8294 {
8295     uint64 aarch64OfstRegIdx = offset;
8296     aarch64OfstRegIdx = (aarch64OfstRegIdx << 1);
8297     if (size == k64BitSize) {
8298         ++aarch64OfstRegIdx;
8299     }
8300     DEBUG_ASSERT(size == k32BitSize || size == k64BitSize, "ofStOpnd size check");
8301     auto it = hashOfstOpndTable.find(aarch64OfstRegIdx);
8302     if (it != hashOfstOpndTable.end()) {
8303         return *it->second;
8304     }
8305     OfstOperand *res = &CreateOfstOpnd(offset, size);
8306     hashOfstOpndTable[aarch64OfstRegIdx] = res;
8307     return *res;
8308 }
8309 
SelectAddrofAfterRa(Operand & result,StImmOperand & stImm,std::vector<Insn * > & rematInsns)8310 void AArch64CGFunc::SelectAddrofAfterRa(Operand &result, StImmOperand &stImm, std::vector<Insn *> &rematInsns)
8311 {
8312     const MIRSymbol *symbol = stImm.GetSymbol();
8313     DEBUG_ASSERT((symbol->GetStorageClass() != kScAuto) || (symbol->GetStorageClass() != kScFormal), "");
8314     Operand *srcOpnd = &result;
8315     rematInsns.emplace_back(&GetInsnBuilder()->BuildInsn(MOP_xadrp, result, stImm));
8316     if (CGOptions::IsPIC() && symbol->NeedPIC()) {
8317         OfstOperand &offset = CreateOfstOpnd(*stImm.GetSymbol(), stImm.GetOffset(), stImm.GetRelocs());
8318         MemOperand &memOpnd = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, GetPointerSize() * kBitsPerByte,
8319                                                  static_cast<RegOperand *>(srcOpnd), nullptr, &offset, nullptr);
8320         rematInsns.emplace_back(
8321             &GetInsnBuilder()->BuildInsn(memOpnd.GetSize() == k64BitSize ? MOP_xldr : MOP_wldr, result, memOpnd));
8322 
8323         if (stImm.GetOffset() > 0) {
8324             ImmOperand &immOpnd = CreateImmOperand(stImm.GetOffset(), result.GetSize(), false);
8325             rematInsns.emplace_back(&GetInsnBuilder()->BuildInsn(MOP_xaddrri12, result, result, immOpnd));
8326             return;
8327         }
8328     } else {
8329         rematInsns.emplace_back(&GetInsnBuilder()->BuildInsn(MOP_xadrpl12, result, *srcOpnd, stImm));
8330     }
8331 }
8332 
GetOrCreateMemOpndAfterRa(const MIRSymbol & symbol,int32 offset,uint32 size,bool needLow12,RegOperand * regOp,std::vector<Insn * > & rematInsns)8333 MemOperand &AArch64CGFunc::GetOrCreateMemOpndAfterRa(const MIRSymbol &symbol, int32 offset, uint32 size, bool needLow12,
8334                                                      RegOperand *regOp, std::vector<Insn *> &rematInsns)
8335 {
8336     MIRStorageClass storageClass = symbol.GetStorageClass();
8337     if ((storageClass == kScGlobal) || (storageClass == kScExtern)) {
8338         StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8339         RegOperand &stAddrOpnd = *regOp;
8340         SelectAddrofAfterRa(stAddrOpnd, stOpnd, rematInsns);
8341         /* MemOperand::AddrMode_B_OI */
8342         return *CreateMemOperand(MemOperand::kAddrModeBOi, size, stAddrOpnd, nullptr,
8343                                  &GetOrCreateOfstOpnd(0, k32BitSize), &symbol);
8344     } else if ((storageClass == kScPstatic) || (storageClass == kScFstatic)) {
8345         if (symbol.GetSKind() == kStConst) {
8346             DEBUG_ASSERT(offset == 0, "offset should be 0 for constant literals");
8347             return *CreateMemOperand(MemOperand::kAddrModeLiteral, size, symbol);
8348         } else {
8349             if (needLow12) {
8350                 StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8351                 RegOperand &stAddrOpnd = *regOp;
8352                 SelectAddrofAfterRa(stAddrOpnd, stOpnd, rematInsns);
8353                 return *CreateMemOperand(MemOperand::kAddrModeBOi, size, stAddrOpnd, nullptr,
8354                                          &GetOrCreateOfstOpnd(0, k32BitSize), &symbol);
8355             } else {
8356                 StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8357                 RegOperand &stAddrOpnd = *regOp;
8358                 Insn &insn = GetInsnBuilder()->BuildInsn(MOP_xadrp, stAddrOpnd, stOpnd);
8359                 rematInsns.emplace_back(&insn);
8360                 return *CreateMemOperand(MemOperand::kAddrModeLo12Li, size, stAddrOpnd, nullptr,
8361                                          &GetOrCreateOfstOpnd(static_cast<uint64>(offset), k32BitSize), &symbol);
8362             }
8363         }
8364     } else {
8365         CHECK_FATAL(false, "NYI");
8366     }
8367 }
8368 
GetOrCreateMemOpnd(const MIRSymbol & symbol,int64 offset,uint32 size,bool forLocalRef,bool needLow12,RegOperand * regOp)8369 MemOperand &AArch64CGFunc::GetOrCreateMemOpnd(const MIRSymbol &symbol, int64 offset, uint32 size, bool forLocalRef,
8370                                               bool needLow12, RegOperand *regOp)
8371 {
8372     MIRStorageClass storageClass = symbol.GetStorageClass();
8373     if ((storageClass == kScAuto) || (storageClass == kScFormal)) {
8374         AArch64SymbolAlloc *symLoc =
8375             static_cast<AArch64SymbolAlloc *>(GetMemlayout()->GetSymAllocInfo(symbol.GetStIndex()));
8376         if (forLocalRef) {
8377             auto p = GetMemlayout()->GetLocalRefLocMap().find(symbol.GetStIdx());
8378             CHECK_FATAL(p != GetMemlayout()->GetLocalRefLocMap().end(), "sym loc should have been defined");
8379             symLoc = static_cast<AArch64SymbolAlloc *>(p->second);
8380         }
8381         DEBUG_ASSERT(symLoc != nullptr, "sym loc should have been defined");
8382         /* At this point, we don't know which registers the callee needs to save. */
8383         DEBUG_ASSERT((IsFPLRAddedToCalleeSavedList() || (SizeOfCalleeSaved() == 0)),
8384                      "CalleeSaved won't be known until after Register Allocation");
8385         StIdx idx = symbol.GetStIdx();
8386         auto it = memOpndsRequiringOffsetAdjustment.find(idx);
8387         DEBUG_ASSERT((!IsFPLRAddedToCalleeSavedList() ||
8388                       ((it != memOpndsRequiringOffsetAdjustment.end()) || (storageClass == kScFormal))),
8389                      "Memory operand of this symbol should have been added to the hash table");
8390         int32 stOffset = GetBaseOffset(*symLoc);
8391         if (it != memOpndsRequiringOffsetAdjustment.end()) {
8392             if (GetMemlayout()->IsLocalRefLoc(symbol)) {
8393                 if (!forLocalRef) {
8394                     return *(it->second);
8395                 }
8396             } else {
8397                 Operand *offOpnd = (it->second)->GetOffset();
8398                 DEBUG_ASSERT(offOpnd != nullptr, "offOpnd should not be nullptr");
8399                 if (((static_cast<OfstOperand *>(offOpnd))->GetOffsetValue() == (stOffset + offset)) &&
8400                     (it->second->GetSize() == size)) {
8401                     return *(it->second);
8402                 }
8403             }
8404         }
8405         it = memOpndsForStkPassedArguments.find(idx);
8406         if (it != memOpndsForStkPassedArguments.end()) {
8407             if (GetMemlayout()->IsLocalRefLoc(symbol)) {
8408                 if (!forLocalRef) {
8409                     return *(it->second);
8410                 }
8411             } else {
8412                 return *(it->second);
8413             }
8414         }
8415 
8416         RegOperand *baseOpnd = static_cast<RegOperand *>(GetBaseReg(*symLoc));
8417         int32 totalOffset = stOffset + static_cast<int32>(offset);
8418         /* needs a fresh copy of ImmOperand as we may adjust its offset at a later stage. */
8419         OfstOperand *offsetOpnd = nullptr;
8420         if (CGOptions::IsBigEndian()) {
8421             if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed && size < k64BitSize) {
8422                 offsetOpnd = &CreateOfstOpnd(k4BitSize + static_cast<uint32>(totalOffset), k64BitSize);
8423             } else {
8424                 offsetOpnd = &CreateOfstOpnd(static_cast<uint64>(static_cast<int64>(totalOffset)), k64BitSize);
8425             }
8426         } else {
8427             offsetOpnd = &CreateOfstOpnd(static_cast<uint64>(static_cast<int64>(totalOffset)), k64BitSize);
8428         }
8429         if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed &&
8430             MemOperand::IsPIMMOffsetOutOfRange(totalOffset, size)) {
8431             ImmOperand *offsetOprand = &CreateImmOperand(totalOffset, k64BitSize, true, kUnAdjustVary);
8432             Operand *resImmOpnd = &SelectCopy(*offsetOprand, PTY_i64, PTY_i64);
8433             return *CreateMemOperand(MemOperand::kAddrModeBOrX, size, *baseOpnd, static_cast<RegOperand &>(*resImmOpnd),
8434                                      nullptr, symbol, true);
8435         } else {
8436             if (symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) {
8437                 offsetOpnd->SetVary(kUnAdjustVary);
8438             }
8439             MemOperand *res = CreateMemOperand(MemOperand::kAddrModeBOi, size, *baseOpnd, nullptr, offsetOpnd, &symbol);
8440             if ((symbol.GetType()->GetKind() != kTypeClass) && !forLocalRef) {
8441                 memOpndsRequiringOffsetAdjustment[idx] = res;
8442             }
8443             return *res;
8444         }
8445     } else if ((storageClass == kScGlobal) || (storageClass == kScExtern)) {
8446         StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8447         if (!regOp) {
8448             regOp = static_cast<RegOperand *>(&CreateRegisterOperandOfType(PTY_u64));
8449         }
8450         RegOperand &stAddrOpnd = *regOp;
8451         SelectAddrof(stAddrOpnd, stOpnd);
8452         /* MemOperand::AddrMode_B_OI */
8453         return *CreateMemOperand(MemOperand::kAddrModeBOi, size, stAddrOpnd, nullptr,
8454                                  &GetOrCreateOfstOpnd(0, k32BitSize), &symbol);
8455     } else if ((storageClass == kScPstatic) || (storageClass == kScFstatic)) {
8456         return CreateMemOpndForStatic(symbol, offset, size, needLow12, regOp);
8457     } else {
8458         CHECK_FATAL(false, "NYI");
8459     }
8460 }
8461 
CreateMemOpndForStatic(const MIRSymbol & symbol,int64 offset,uint32 size,bool needLow12,RegOperand * regOp)8462 MemOperand &AArch64CGFunc::CreateMemOpndForStatic(const MIRSymbol &symbol, int64 offset, uint32 size, bool needLow12,
8463                                                   RegOperand *regOp)
8464 {
8465     if (symbol.GetSKind() == kStConst) {
8466         DEBUG_ASSERT(offset == 0, "offset should be 0 for constant literals");
8467         return *CreateMemOperand(MemOperand::kAddrModeLiteral, size, symbol);
8468     } else {
8469         /* not guaranteed align for uninitialized symbol */
8470         if (needLow12 || (!symbol.IsConst() && CGOptions::IsPIC())) {
8471             StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8472             if (!regOp) {
8473                 regOp = static_cast<RegOperand *>(&CreateRegisterOperandOfType(PTY_u64));
8474             }
8475             RegOperand &stAddrOpnd = *regOp;
8476             SelectAddrof(stAddrOpnd, stOpnd);
8477             return *CreateMemOperand(MemOperand::kAddrModeBOi, size, stAddrOpnd, nullptr,
8478                                      &GetOrCreateOfstOpnd(0, k32BitSize), &symbol);
8479         } else {
8480             StImmOperand &stOpnd = CreateStImmOperand(symbol, offset, 0);
8481             if (!regOp) {
8482                 regOp = static_cast<RegOperand *>(&CreateRegisterOperandOfType(PTY_u64));
8483             }
8484             RegOperand &stAddrOpnd = *regOp;
8485             Insn &insn = GetInsnBuilder()->BuildInsn(MOP_xadrp, stAddrOpnd, stOpnd);
8486             GetCurBB()->AppendInsn(insn);
8487             if (GetCG()->GetOptimizeLevel() == CGOptions::kLevel0 ||
8488                 ((size == k64BitSize) && (offset % static_cast<int64>(k8BitSizeInt) != 0)) ||
8489                 ((size == k32BitSize) && (offset % static_cast<int64>(k4BitSizeInt) != 0)) ||
8490                 ((size == k16BitSize) && (offset % static_cast<int64>(k2BitSizeInt) != 0))) {
8491                 GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, stAddrOpnd, stAddrOpnd, stOpnd));
8492                 return *CreateMemOperand(MemOperand::kAddrModeBOi, size, stAddrOpnd, nullptr,
8493                                          &GetOrCreateOfstOpnd(static_cast<uint64>(0), k32BitSize), nullptr);
8494             }
8495 
8496             return *CreateMemOperand(MemOperand::kAddrModeLo12Li, size, stAddrOpnd, nullptr,
8497                                      &GetOrCreateOfstOpnd(static_cast<uint64>(offset), k32BitSize), &symbol);
8498         }
8499     }
8500 }
8501 
HashMemOpnd(MemOperand & tMemOpnd)8502 MemOperand &AArch64CGFunc::HashMemOpnd(MemOperand &tMemOpnd)
8503 {
8504     auto it = hashMemOpndTable.find(tMemOpnd);
8505     if (it != hashMemOpndTable.end()) {
8506         return *(it->second);
8507     }
8508     auto *res = memPool->New<MemOperand>(tMemOpnd);
8509     hashMemOpndTable[tMemOpnd] = res;
8510     return *res;
8511 }
8512 
GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode mode,uint32 size,RegOperand * base,RegOperand * index,ImmOperand * offset,const MIRSymbol * st)8513 MemOperand &AArch64CGFunc::GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand *base,
8514                                               RegOperand *index, ImmOperand *offset, const MIRSymbol *st)
8515 {
8516     DEBUG_ASSERT(base != nullptr, "nullptr check");
8517     MemOperand tMemOpnd(mode, size, *base, index, offset, st);
8518     if (base->GetRegisterNumber() == RFP || base->GetRegisterNumber() == RSP) {
8519         tMemOpnd.SetStackMem(true);
8520     }
8521     return HashMemOpnd(tMemOpnd);
8522 }
8523 
GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode mode,uint32 size,RegOperand * base,RegOperand * index,int32 shift,bool isSigned)8524 MemOperand &AArch64CGFunc::GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand *base,
8525                                               RegOperand *index, int32 shift, bool isSigned)
8526 {
8527     DEBUG_ASSERT(base != nullptr, "nullptr check");
8528     MemOperand tMemOpnd(mode, size, *base, *index, shift, isSigned);
8529     if (base->GetRegisterNumber() == RFP || base->GetRegisterNumber() == RSP) {
8530         tMemOpnd.SetStackMem(true);
8531     }
8532     return HashMemOpnd(tMemOpnd);
8533 }
8534 
GetOrCreateMemOpnd(MemOperand & oldMem)8535 MemOperand &AArch64CGFunc::GetOrCreateMemOpnd(MemOperand &oldMem)
8536 {
8537     return HashMemOpnd(oldMem);
8538 }
8539 
8540 /* offset: base offset from FP or SP */
CreateMemOpnd(RegOperand & baseOpnd,int64 offset,uint32 size)8541 MemOperand &AArch64CGFunc::CreateMemOpnd(RegOperand &baseOpnd, int64 offset, uint32 size)
8542 {
8543     OfstOperand &offsetOpnd = CreateOfstOpnd(static_cast<uint64>(offset), k32BitSize);
8544     /* do not need to check bit size rotate of sign immediate */
8545     bool checkSimm = (offset > kMinSimm64 && offset < kMaxSimm64Pair);
8546     if (!checkSimm && !ImmOperand::IsInBitSizeRot(kMaxImmVal12Bits, offset)) {
8547         Operand *resImmOpnd = &SelectCopy(CreateImmOperand(offset, k32BitSize, true), PTY_i32, PTY_i32);
8548         return *CreateMemOperand(MemOperand::kAddrModeBOrX, size, baseOpnd, static_cast<RegOperand *>(resImmOpnd),
8549                                  nullptr, nullptr);
8550     } else {
8551         return *CreateMemOperand(MemOperand::kAddrModeBOi, size, baseOpnd, nullptr, &offsetOpnd, nullptr);
8552     }
8553 }
8554 
8555 /* offset: base offset + #:lo12:Label+immediate */
CreateMemOpnd(RegOperand & baseOpnd,int64 offset,uint32 size,const MIRSymbol & sym)8556 MemOperand &AArch64CGFunc::CreateMemOpnd(RegOperand &baseOpnd, int64 offset, uint32 size, const MIRSymbol &sym)
8557 {
8558     OfstOperand &offsetOpnd = CreateOfstOpnd(static_cast<uint64>(offset), k32BitSize);
8559     DEBUG_ASSERT(ImmOperand::IsInBitSizeRot(kMaxImmVal12Bits, offset), "");
8560     return *CreateMemOperand(MemOperand::kAddrModeBOi, size, baseOpnd, nullptr, &offsetOpnd, &sym);
8561 }
8562 
GenStructParamIndex(RegOperand & base,const BaseNode & indexExpr,int shift,PrimType baseType)8563 RegOperand &AArch64CGFunc::GenStructParamIndex(RegOperand &base, const BaseNode &indexExpr, int shift,
8564                                                PrimType baseType)
8565 {
8566     RegOperand *index = &LoadIntoRegister(*HandleExpr(indexExpr, *(indexExpr.Opnd(0))), PTY_a64);
8567     RegOperand *srcOpnd = &CreateRegisterOperandOfType(PTY_a64);
8568     ImmOperand *imm = &CreateImmOperand(PTY_a64, shift);
8569     SelectShift(*srcOpnd, *index, *imm, kShiftLeft, PTY_a64);
8570     RegOperand *result = &CreateRegisterOperandOfType(PTY_a64);
8571     SelectAdd(*result, base, *srcOpnd, PTY_a64);
8572 
8573     OfstOperand *offopnd = &CreateOfstOpnd(0, k32BitSize);
8574     MemOperand &mo = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, result, nullptr, offopnd, nullptr);
8575     RegOperand &structAddr = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
8576     GetCurBB()->AppendInsn(
8577         GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(baseType), baseType), structAddr, mo));
8578     return structAddr;
8579 }
8580 
8581 /*
8582  *  case 1: iread a64 <* <* void>> 0 (add a64 (
8583  *  addrof a64 $__reg_jni_func_tab$$libcore_all_bytecode,
8584  *  mul a64 (
8585  *    cvt a64 i32 (constval i32 21),
8586  *    constval a64 8)))
8587  *
8588  * case 2 : iread u32 <* u8> 0 (add a64 (regread a64 %61, constval a64 3))
8589  * case 3 : iread u32 <* u8> 0 (add a64 (regread a64 %61, regread a64 %65))
8590  * case 4 : iread u32 <* u8> 0 (add a64 (cvt a64 i32(regread  %n)))
8591  */
CheckAndCreateExtendMemOpnd(PrimType ptype,const BaseNode & addrExpr,int64 offset,AArch64isa::MemoryOrdering memOrd)8592 MemOperand *AArch64CGFunc::CheckAndCreateExtendMemOpnd(PrimType ptype, const BaseNode &addrExpr, int64 offset,
8593                                                        AArch64isa::MemoryOrdering memOrd)
8594 {
8595     aggParamReg = nullptr;
8596     if (memOrd != AArch64isa::kMoNone || addrExpr.GetOpCode() != OP_add || offset != 0) {
8597         return nullptr;
8598     }
8599     BaseNode *baseExpr = addrExpr.Opnd(0);
8600     BaseNode *addendExpr = addrExpr.Opnd(1);
8601 
8602     if (baseExpr->GetOpCode() == OP_regread) {
8603         /* case 2 */
8604         if (addendExpr->GetOpCode() == OP_constval) {
8605             DEBUG_ASSERT(addrExpr.GetNumOpnds() == kOpndNum2, "Unepect expr operand in CheckAndCreateExtendMemOpnd");
8606             ConstvalNode *constOfstNode = static_cast<ConstvalNode *>(addendExpr);
8607             DEBUG_ASSERT(constOfstNode->GetConstVal()->GetKind() == kConstInt, "expect MIRIntConst");
8608             MIRIntConst *intOfst = safe_cast<MIRIntConst>(constOfstNode->GetConstVal());
8609             CHECK_FATAL(intOfst != nullptr, "just checking");
8610             /* discard large offset and negative offset */
8611             if (intOfst->GetExtValue() > INT32_MAX || intOfst->IsNegative()) {
8612                 return nullptr;
8613             }
8614             uint32 scale = static_cast<uint32>(intOfst->GetExtValue());
8615             OfstOperand &ofstOpnd = GetOrCreateOfstOpnd(scale, k32BitSize);
8616             uint32 dsize = GetPrimTypeBitSize(ptype);
8617             MemOperand *memOpnd =
8618                 &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, GetPrimTypeBitSize(ptype),
8619                                     SelectRegread(*static_cast<RegreadNode *>(baseExpr)), nullptr, &ofstOpnd, nullptr);
8620             return IsOperandImmValid(PickLdInsn(dsize, ptype), memOpnd, kInsnSecondOpnd) ? memOpnd : nullptr;
8621             /* case 3 */
8622         } else if (addendExpr->GetOpCode() == OP_regread) {
8623             CHECK_FATAL(addrExpr.GetNumOpnds() == kOpndNum2, "Unepect expr operand in CheckAndCreateExtendMemOpnd");
8624             if (GetPrimTypeSize(baseExpr->GetPrimType()) != GetPrimTypeSize(addendExpr->GetPrimType())) {
8625                 return nullptr;
8626             }
8627 
8628             auto *baseReg = SelectRegread(*static_cast<RegreadNode *>(baseExpr));
8629             auto *indexReg = SelectRegread(*static_cast<RegreadNode *>(addendExpr));
8630             MemOperand *memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype), baseReg,
8631                                                       indexReg, nullptr, nullptr);
8632             if (CGOptions::IsArm64ilp32() && IsSignedInteger(addendExpr->GetPrimType())) {
8633                 memOpnd->SetExtend(memOpnd->GetExtend() | MemOperand::ExtendInfo::kSignExtend);
8634             }
8635             return memOpnd;
8636             /* case 4 */
8637         } else if (addendExpr->GetOpCode() == OP_cvt && addendExpr->GetNumOpnds() == 1) {
8638             int shiftAmount = 0;
8639             BaseNode *cvtRegreadNode = addendExpr->Opnd(kInsnFirstOpnd);
8640             if (cvtRegreadNode->GetOpCode() == OP_regread && cvtRegreadNode->IsLeaf()) {
8641                 uint32 fromSize = GetPrimTypeBitSize(cvtRegreadNode->GetPrimType());
8642                 uint32 toSize = GetPrimTypeBitSize(addendExpr->GetPrimType());
8643                 if (toSize < fromSize) {
8644                     return nullptr;
8645                 }
8646 
8647                 MemOperand *memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype),
8648                                                           SelectRegread(*static_cast<RegreadNode *>(baseExpr)),
8649                                                           SelectRegread(*static_cast<RegreadNode *>(cvtRegreadNode)),
8650                                                           shiftAmount, toSize != fromSize);
8651                 return memOpnd;
8652             }
8653         }
8654     }
8655     if (addendExpr->GetOpCode() != OP_mul || !IsPrimitiveInteger(ptype)) {
8656         return nullptr;
8657     }
8658     BaseNode *indexExpr, *scaleExpr;
8659     indexExpr = addendExpr->Opnd(0);
8660     scaleExpr = addendExpr->Opnd(1);
8661     if (scaleExpr->GetOpCode() != OP_constval) {
8662         return nullptr;
8663     }
8664     ConstvalNode *constValNode = static_cast<ConstvalNode *>(scaleExpr);
8665     CHECK_FATAL(constValNode->GetConstVal()->GetKind() == kConstInt, "expect MIRIntConst");
8666     MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(constValNode->GetConstVal());
8667     CHECK_FATAL(mirIntConst != nullptr, "just checking");
8668     int32 scale = mirIntConst->GetExtValue();
8669     if (scale < 0) {
8670         return nullptr;
8671     }
8672     uint32 unsignedScale = static_cast<uint32>(scale);
8673     if (unsignedScale != GetPrimTypeSize(ptype) || indexExpr->GetOpCode() != OP_cvt) {
8674         return nullptr;
8675     }
8676     /* 8 is 1 << 3; 4 is 1 << 2; 2 is 1 << 1; 1 is 1 << 0 */
8677     int32 shift = (unsignedScale == 8) ? 3 : ((unsignedScale == 4) ? 2 : ((unsignedScale == 2) ? 1 : 0));
8678     RegOperand &base = static_cast<RegOperand &>(LoadIntoRegister(*HandleExpr(addrExpr, *baseExpr), PTY_a64));
8679     TypeCvtNode *typeCvtNode = static_cast<TypeCvtNode *>(indexExpr);
8680     PrimType fromType = typeCvtNode->FromType();
8681     PrimType toType = typeCvtNode->GetPrimType();
8682     if (isAggParamInReg) {
8683         aggParamReg = &GenStructParamIndex(base, *indexExpr, shift, ptype);
8684         return nullptr;
8685     }
8686     MemOperand *memOpnd = nullptr;
8687     if ((fromType == PTY_i32) && (toType == PTY_a64)) {
8688         RegOperand &index =
8689             static_cast<RegOperand &>(LoadIntoRegister(*HandleExpr(*indexExpr, *indexExpr->Opnd(0)), PTY_i32));
8690         memOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype), &base, &index, shift, true);
8691     } else if ((fromType == PTY_u32) && (toType == PTY_a64)) {
8692         RegOperand &index =
8693             static_cast<RegOperand &>(LoadIntoRegister(*HandleExpr(*indexExpr, *indexExpr->Opnd(0)), PTY_u32));
8694         memOpnd =
8695             &GetOrCreateMemOpnd(MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype), &base, &index, shift, false);
8696     }
8697     return memOpnd;
8698 }
8699 
CreateNonExtendMemOpnd(PrimType ptype,const BaseNode & parent,BaseNode & addrExpr,int64 offset)8700 MemOperand &AArch64CGFunc::CreateNonExtendMemOpnd(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr,
8701                                                   int64 offset)
8702 {
8703     Operand *addrOpnd = nullptr;
8704     if ((addrExpr.GetOpCode() == OP_add || addrExpr.GetOpCode() == OP_sub) &&
8705         addrExpr.Opnd(1)->GetOpCode() == OP_constval) {
8706         addrOpnd = HandleExpr(addrExpr, *addrExpr.Opnd(0));
8707         ConstvalNode *constOfstNode = static_cast<ConstvalNode *>(addrExpr.Opnd(1));
8708         DEBUG_ASSERT(constOfstNode->GetConstVal()->GetKind() == kConstInt, "expect MIRIntConst");
8709         MIRIntConst *intOfst = safe_cast<MIRIntConst>(constOfstNode->GetConstVal());
8710         CHECK_FATAL(intOfst != nullptr, "just checking");
8711         offset = (addrExpr.GetOpCode() == OP_add) ? offset + intOfst->GetSXTValue() : offset - intOfst->GetSXTValue();
8712     } else {
8713         addrOpnd = HandleExpr(parent, addrExpr);
8714     }
8715     addrOpnd = static_cast<RegOperand *>(&LoadIntoRegister(*addrOpnd, PTY_a64));
8716     Insn *lastInsn = GetCurBB() == nullptr ? nullptr : GetCurBB()->GetLastMachineInsn();
8717     if ((addrExpr.GetOpCode() == OP_CG_array_elem_add) && (offset == 0) && lastInsn &&
8718         (lastInsn->GetMachineOpcode() == MOP_xadrpl12) &&
8719         (&lastInsn->GetOperand(kInsnFirstOpnd) == &lastInsn->GetOperand(kInsnSecondOpnd))) {
8720         Operand &opnd = lastInsn->GetOperand(kInsnThirdOpnd);
8721         StImmOperand &stOpnd = static_cast<StImmOperand &>(opnd);
8722 
8723         OfstOperand &ofstOpnd = GetOrCreateOfstOpnd(static_cast<uint64>(stOpnd.GetOffset()), k32BitSize);
8724         MemOperand &tmpMemOpnd =
8725             GetOrCreateMemOpnd(MemOperand::kAddrModeLo12Li, GetPrimTypeBitSize(ptype),
8726                                static_cast<RegOperand *>(addrOpnd), nullptr, &ofstOpnd, stOpnd.GetSymbol());
8727         if (GetCurBB() && GetCurBB()->GetLastMachineInsn()) {
8728             GetCurBB()->RemoveInsn(*GetCurBB()->GetLastMachineInsn());
8729         }
8730         return tmpMemOpnd;
8731     } else {
8732         OfstOperand &ofstOpnd = GetOrCreateOfstOpnd(static_cast<uint64>(offset), k64BitSize);
8733         return GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, GetPrimTypeBitSize(ptype),
8734                                   static_cast<RegOperand *>(addrOpnd), nullptr, &ofstOpnd, nullptr);
8735     }
8736 }
8737 
8738 /*
8739  * Create a memory operand with specified data type and memory ordering, making
8740  * use of aarch64 extend register addressing mode when possible.
8741  */
CreateMemOpnd(PrimType ptype,const BaseNode & parent,BaseNode & addrExpr,int64 offset,AArch64isa::MemoryOrdering memOrd)8742 MemOperand &AArch64CGFunc::CreateMemOpnd(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr, int64 offset,
8743                                          AArch64isa::MemoryOrdering memOrd)
8744 {
8745     MemOperand *memOpnd = CheckAndCreateExtendMemOpnd(ptype, addrExpr, offset, memOrd);
8746     if (memOpnd != nullptr) {
8747         return *memOpnd;
8748     }
8749     return CreateNonExtendMemOpnd(ptype, parent, addrExpr, offset);
8750 }
8751 
CreateMemOpndOrNull(PrimType ptype,const BaseNode & parent,BaseNode & addrExpr,int64 offset,AArch64isa::MemoryOrdering memOrd)8752 MemOperand *AArch64CGFunc::CreateMemOpndOrNull(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr, int64 offset,
8753                                                AArch64isa::MemoryOrdering memOrd)
8754 {
8755     MemOperand *memOpnd = CheckAndCreateExtendMemOpnd(ptype, addrExpr, offset, memOrd);
8756     if (memOpnd != nullptr) {
8757         return memOpnd;
8758     } else if (aggParamReg != nullptr) {
8759         return nullptr;
8760     }
8761     return &CreateNonExtendMemOpnd(ptype, parent, addrExpr, offset);
8762 }
8763 
GetOrCreateFuncNameOpnd(const MIRSymbol & symbol) const8764 Operand &AArch64CGFunc::GetOrCreateFuncNameOpnd(const MIRSymbol &symbol) const
8765 {
8766     return *memPool->New<FuncNameOperand>(symbol);
8767 }
8768 
GetOrCreateRflag()8769 Operand &AArch64CGFunc::GetOrCreateRflag()
8770 {
8771     if (rcc == nullptr) {
8772         rcc = &CreateRflagOperand();
8773     }
8774     return *rcc;
8775 }
8776 
GetRflag() const8777 const Operand *AArch64CGFunc::GetRflag() const
8778 {
8779     return rcc;
8780 }
8781 
GetOrCreatevaryreg()8782 RegOperand &AArch64CGFunc::GetOrCreatevaryreg()
8783 {
8784     if (vary == nullptr) {
8785         regno_t vRegNO = NewVReg(kRegTyVary, k8ByteSize);
8786         vary = &CreateVirtualRegisterOperand(vRegNO);
8787     }
8788     return *vary;
8789 }
8790 
8791 /* the first operand in opndvec is return opnd */
SelectLibCall(const std::string & funcName,std::vector<Operand * > & opndVec,PrimType primType,PrimType retPrimType,bool is2ndRet)8792 void AArch64CGFunc::SelectLibCall(const std::string &funcName, std::vector<Operand *> &opndVec, PrimType primType,
8793                                   PrimType retPrimType, bool is2ndRet)
8794 {
8795     std::vector<PrimType> pt;
8796     pt.push_back(retPrimType);
8797     for (size_t i = 0; i < opndVec.size(); ++i) {
8798         pt.push_back(primType);
8799     }
8800     SelectLibCallNArg(funcName, opndVec, pt, retPrimType, is2ndRet);
8801     return;
8802 }
8803 
SelectLibCallNArg(const std::string & funcName,std::vector<Operand * > & opndVec,std::vector<PrimType> pt,PrimType retPrimType,bool is2ndRet)8804 void AArch64CGFunc::SelectLibCallNArg(const std::string &funcName, std::vector<Operand *> &opndVec,
8805                                       std::vector<PrimType> pt, PrimType retPrimType, bool is2ndRet)
8806 {
8807     std::string newName = funcName;
8808     // Check whether we have a maple version of libcall and we want to use it instead.
8809     if (!CGOptions::IsDuplicateAsmFileEmpty() && asmMap.find(funcName) != asmMap.end()) {
8810         newName = asmMap.at(funcName);
8811     }
8812     MIRSymbol *st = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
8813     st->SetNameStrIdx(newName);
8814     st->SetStorageClass(kScExtern);
8815     st->SetSKind(kStFunc);
8816     /* setup the type of the callee function */
8817     std::vector<TyIdx> vec;
8818     std::vector<TypeAttrs> vecAt;
8819     for (size_t i = 1; i < opndVec.size(); ++i) {
8820         (void)vec.emplace_back(GlobalTables::GetTypeTable().GetTypeTable()[static_cast<size_t>(pt[i])]->GetTypeIndex());
8821         vecAt.emplace_back(TypeAttrs());
8822     }
8823 
8824     MIRType *retType = GlobalTables::GetTypeTable().GetTypeTable().at(static_cast<size_t>(retPrimType));
8825     st->SetTyIdx(GetBecommon().BeGetOrCreateFunctionType(retType->GetTypeIndex(), vec, vecAt)->GetTypeIndex());
8826 
8827     if (GetCG()->GenerateVerboseCG()) {
8828         const std::string &comment = "lib call : " + newName;
8829         GetCurBB()->AppendInsn(CreateCommentInsn(comment));
8830     }
8831     // only create c lib call here
8832     AArch64CallConvImpl parmLocator(GetBecommon());
8833     CCLocInfo ploc;
8834     /* setup actual parameters */
8835     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
8836     for (size_t i = 1; i < opndVec.size(); ++i) {
8837         DEBUG_ASSERT(pt[i] != PTY_void, "primType check");
8838         MIRType *ty = GlobalTables::GetTypeTable().GetTypeTable()[static_cast<size_t>(pt[i])];
8839         Operand *stOpnd = opndVec[i];
8840         if (stOpnd->GetKind() != Operand::kOpdRegister) {
8841             stOpnd = &SelectCopy(*stOpnd, pt[i], pt[i]);
8842         }
8843         RegOperand *expRegOpnd = static_cast<RegOperand *>(stOpnd);
8844         parmLocator.LocateNextParm(*ty, ploc);
8845         if (ploc.reg0 != 0) { /* load to the register */
8846             RegOperand &parmRegOpnd = GetOrCreatePhysicalRegisterOperand(
8847                 static_cast<AArch64reg>(ploc.reg0), expRegOpnd->GetSize(), GetRegTyFromPrimTy(pt[i]));
8848             SelectCopy(parmRegOpnd, pt[i], *expRegOpnd, pt[i]);
8849             srcOpnds->PushOpnd(parmRegOpnd);
8850         }
8851         DEBUG_ASSERT(ploc.reg1 == 0, "SelectCall NYI");
8852     }
8853 
8854     MIRSymbol *sym = GetFunction().GetLocalOrGlobalSymbol(st->GetStIdx(), false);
8855     Insn &callInsn = AppendCall(*sym, *srcOpnds);
8856     MIRType *callRetType = GlobalTables::GetTypeTable().GetTypeTable().at(static_cast<int32>(retPrimType));
8857     if (callRetType != nullptr) {
8858         callInsn.SetRetSize(static_cast<uint32>(callRetType->GetSize()));
8859         callInsn.SetIsCallReturnUnsigned(IsUnsignedInteger(callRetType->GetPrimType()));
8860     }
8861     GetFunction().SetHasCall();
8862     /* get return value */
8863     Operand *opnd0 = opndVec[0];
8864     CCLocInfo retMech;
8865     parmLocator.LocateRetVal(*(GlobalTables::GetTypeTable().GetTypeTable().at(retPrimType)), retMech);
8866     if (retMech.GetRegCount() <= 0) {
8867         CHECK_FATAL(false, "should return from register");
8868     }
8869     if (!opnd0->IsRegister()) {
8870         CHECK_FATAL(false, "nyi");
8871     }
8872     RegOperand *regOpnd = static_cast<RegOperand *>(opnd0);
8873     AArch64reg regNum = static_cast<AArch64reg>(is2ndRet ? retMech.GetReg1() : retMech.GetReg0());
8874     if (regOpnd->GetRegisterNumber() != regNum) {
8875         RegOperand &retOpnd =
8876             GetOrCreatePhysicalRegisterOperand(regNum, regOpnd->GetSize(), GetRegTyFromPrimTy(retPrimType));
8877         SelectCopy(*opnd0, retPrimType, retOpnd, retPrimType);
8878     }
8879 }
8880 
GetBaseReg(const SymbolAlloc & symAlloc)8881 RegOperand *AArch64CGFunc::GetBaseReg(const SymbolAlloc &symAlloc)
8882 {
8883     MemSegmentKind sgKind = symAlloc.GetMemSegment()->GetMemSegmentKind();
8884     DEBUG_ASSERT(((sgKind == kMsArgsRegPassed) || (sgKind == kMsLocals) || (sgKind == kMsRefLocals) ||
8885                   (sgKind == kMsArgsToStkPass) || (sgKind == kMsArgsStkPassed)),
8886                  "NYI");
8887 
8888     if (sgKind == kMsArgsStkPassed || sgKind == kMsCold) {
8889         return &GetOrCreatevaryreg();
8890     }
8891 
8892     if (fsp == nullptr) {
8893         fsp = &GetOrCreatePhysicalRegisterOperand(RFP, GetPointerSize() * kBitsPerByte, kRegTyInt);
8894     }
8895     return fsp;
8896 }
8897 
GetBaseOffset(const SymbolAlloc & symbolAlloc)8898 int32 AArch64CGFunc::GetBaseOffset(const SymbolAlloc &symbolAlloc)
8899 {
8900 
8901     const AArch64SymbolAlloc *symAlloc = static_cast<const AArch64SymbolAlloc *>(&symbolAlloc);
8902     // Call Frame layout of AArch64
8903     // Refer to V2 in aarch64_memlayout.h.
8904     // Do Not change this unless you know what you do
8905     // O2 mode refer to V2.1 in  aarch64_memlayout.cpp
8906     const int32 sizeofFplr = static_cast<int32>(2 * kAarch64IntregBytelen);
8907     MemSegmentKind sgKind = symAlloc->GetMemSegment()->GetMemSegmentKind();
8908     AArch64MemLayout *memLayout = static_cast<AArch64MemLayout *>(this->GetMemlayout());
8909     if (sgKind == kMsArgsStkPassed) { /* for callees */
8910         int32 offset = static_cast<int32>(symAlloc->GetOffset());
8911         offset += static_cast<int32>(memLayout->GetSizeOfColdToStk());
8912         return offset;
8913     } else if (sgKind == kMsCold) {
8914         int offset = static_cast<int32>(symAlloc->GetOffset());
8915         return offset;
8916     } else if (sgKind == kMsArgsRegPassed) {
8917         int32 baseOffset;
8918         if (GetCG()->IsLmbc()) {
8919             baseOffset = static_cast<int32>(symAlloc->GetOffset()) +
8920                          static_cast<int32>(memLayout->GetSizeOfRefLocals() +
8921                                             memLayout->SizeOfArgsToStackPass()); /* SP relative */
8922         } else {
8923             baseOffset = static_cast<int32>(memLayout->GetSizeOfLocals() + memLayout->GetSizeOfRefLocals()) +
8924                          static_cast<int32>(symAlloc->GetOffset());
8925         }
8926         return baseOffset + sizeofFplr;
8927     } else if (sgKind == kMsRefLocals) {
8928         int32 baseOffset = static_cast<int32>(symAlloc->GetOffset()) + static_cast<int32>(memLayout->GetSizeOfLocals());
8929         return baseOffset + sizeofFplr;
8930     } else if (sgKind == kMsLocals) {
8931         if (GetCG()->IsLmbc()) {
8932             CHECK_FATAL(false, "invalid lmbc's locals");
8933         }
8934         int32 baseOffset = symAlloc->GetOffset();
8935         return baseOffset + sizeofFplr;
8936     } else if (sgKind == kMsSpillReg) {
8937         int32 baseOffset;
8938         if (GetCG()->IsLmbc()) {
8939             baseOffset = static_cast<int32>(symAlloc->GetOffset()) +
8940                          static_cast<int32>(memLayout->SizeOfArgsRegisterPassed() + memLayout->GetSizeOfRefLocals() +
8941                                             memLayout->SizeOfArgsToStackPass());
8942         } else {
8943             baseOffset = static_cast<int32>(symAlloc->GetOffset()) +
8944                          static_cast<int32>(memLayout->SizeOfArgsRegisterPassed() + memLayout->GetSizeOfLocals() +
8945                                             memLayout->GetSizeOfRefLocals());
8946         }
8947         return baseOffset + sizeofFplr;
8948     } else if (sgKind == kMsArgsToStkPass) { /* this is for callers */
8949         return static_cast<int32>(symAlloc->GetOffset());
8950     } else {
8951         CHECK_FATAL(false, "sgKind check");
8952     }
8953     return 0;
8954 }
8955 
AppendCall(const MIRSymbol & funcSymbol)8956 void AArch64CGFunc::AppendCall(const MIRSymbol &funcSymbol)
8957 {
8958     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
8959     AppendCall(funcSymbol, *srcOpnds);
8960 }
8961 
DBGFixCallFrameLocationOffsets()8962 void AArch64CGFunc::DBGFixCallFrameLocationOffsets()
8963 {
8964     unsigned idx = 0;
8965     for (DBGExprLoc *el : GetDbgCallFrameLocations(true)) {
8966         if (el && el->GetSimpLoc() && el->GetSimpLoc()->GetDwOp() == DW_OP_fbreg) {
8967             SymbolAlloc *symloc = static_cast<SymbolAlloc *>(el->GetSymLoc());
8968             int32 offset = GetBaseOffset(*symloc) - ((idx < AArch64Abi::kNumIntParmRegs) ? GetDbgCallFrameOffset() : 0);
8969             el->SetFboffset(offset);
8970         }
8971         idx++;
8972     }
8973     for (DBGExprLoc *el : GetDbgCallFrameLocations(false)) {
8974         if (el->GetSimpLoc()->GetDwOp() == DW_OP_fbreg) {
8975             SymbolAlloc *symloc = static_cast<SymbolAlloc *>(el->GetSymLoc());
8976             int32 offset = GetBaseOffset(*symloc) - GetDbgCallFrameOffset();
8977             el->SetFboffset(offset);
8978         }
8979     }
8980 }
8981 
SelectAddAfterInsn(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType,bool isDest,Insn & insn)8982 void AArch64CGFunc::SelectAddAfterInsn(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType, bool isDest,
8983                                        Insn &insn)
8984 {
8985     uint32 dsize = GetPrimTypeBitSize(primType);
8986     bool is64Bits = (dsize == k64BitSize);
8987     DEBUG_ASSERT(opnd0.GetKind() == Operand::kOpdRegister, "Spill memory operand should based on register");
8988     DEBUG_ASSERT((opnd1.GetKind() == Operand::kOpdImmediate || opnd1.GetKind() == Operand::kOpdOffset),
8989                  "Spill memory operand should be with a immediate offset.");
8990 
8991     ImmOperand *immOpnd = static_cast<ImmOperand *>(&opnd1);
8992 
8993     MOperator mOpCode = MOP_undef;
8994     Insn *curInsn = &insn;
8995     /* lower 24 bits has 1, higher bits are all 0 */
8996     if (immOpnd->IsInBitSize(kMaxImmVal24Bits, 0)) {
8997         /* lower 12 bits and higher 12 bits both has 1 */
8998         Operand *newOpnd0 = &opnd0;
8999         if (!(immOpnd->IsInBitSize(kMaxImmVal12Bits, 0) || immOpnd->IsInBitSize(kMaxImmVal12Bits, kMaxImmVal12Bits))) {
9000             /* process higher 12 bits */
9001             ImmOperand &immOpnd2 =
9002                 CreateImmOperand(static_cast<int64>(static_cast<uint64>(immOpnd->GetValue()) >> kMaxImmVal12Bits),
9003                                  immOpnd->GetSize(), immOpnd->IsSignedValue());
9004             mOpCode = is64Bits ? MOP_xaddrri24 : MOP_waddrri24;
9005             BitShiftOperand &shiftopnd = CreateBitShiftOperand(BitShiftOperand::kLSL, kShiftAmount12, k64BitSize);
9006             Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, opnd0, immOpnd2, shiftopnd);
9007             DEBUG_ASSERT(IsOperandImmValid(mOpCode, &immOpnd2, kInsnThirdOpnd), "immOpnd2 appears invalid");
9008             if (isDest) {
9009                 insn.GetBB()->InsertInsnAfter(insn, newInsn);
9010             } else {
9011                 insn.GetBB()->InsertInsnBefore(insn, newInsn);
9012             }
9013             /* get lower 12 bits value */
9014             immOpnd->ModuloByPow2(static_cast<int32>(kMaxImmVal12Bits));
9015             newOpnd0 = &resOpnd;
9016             curInsn = &newInsn;
9017         }
9018         /* process lower 12 bits value */
9019         mOpCode = is64Bits ? MOP_xaddrri12 : MOP_waddrri12;
9020         Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, *newOpnd0, *immOpnd);
9021         DEBUG_ASSERT(IsOperandImmValid(mOpCode, immOpnd, kInsnThirdOpnd), "immOpnd appears invalid");
9022         if (isDest) {
9023             insn.GetBB()->InsertInsnAfter(*curInsn, newInsn);
9024         } else {
9025             insn.GetBB()->InsertInsnBefore(insn, newInsn);
9026         }
9027     } else {
9028         /* load into register */
9029         RegOperand &movOpnd = GetOrCreatePhysicalRegisterOperand(R16, dsize, kRegTyInt);
9030         mOpCode = is64Bits ? MOP_xmovri64 : MOP_wmovri32;
9031         Insn &movInsn = GetInsnBuilder()->BuildInsn(mOpCode, movOpnd, *immOpnd);
9032         mOpCode = is64Bits ? MOP_xaddrrr : MOP_waddrrr;
9033         Insn &newInsn = GetInsnBuilder()->BuildInsn(mOpCode, resOpnd, opnd0, movOpnd);
9034         if (isDest) {
9035             (void)insn.GetBB()->InsertInsnAfter(insn, newInsn);
9036             (void)insn.GetBB()->InsertInsnAfter(insn, movInsn);
9037         } else {
9038             (void)insn.GetBB()->InsertInsnBefore(insn, movInsn);
9039             (void)insn.GetBB()->InsertInsnBefore(insn, newInsn);
9040         }
9041     }
9042 }
9043 
AdjustMemOperandIfOffsetOutOfRange(MemOperand * memOpnd,regno_t vrNum,bool isDest,Insn & insn,AArch64reg regNum,bool & isOutOfRange)9044 MemOperand *AArch64CGFunc::AdjustMemOperandIfOffsetOutOfRange(MemOperand *memOpnd, regno_t vrNum, bool isDest,
9045                                                               Insn &insn, AArch64reg regNum, bool &isOutOfRange)
9046 {
9047     if (vrNum >= vReg.VRegTableSize()) {
9048         CHECK_FATAL(false, "index out of range in AArch64CGFunc::AdjustMemOperandIfOffsetOutOfRange");
9049     }
9050     uint32 dataSize = GetOrCreateVirtualRegisterOperand(vrNum).GetSize();
9051     if (IsImmediateOffsetOutOfRange(*memOpnd, dataSize) && CheckIfSplitOffsetWithAdd(*memOpnd, dataSize)) {
9052         isOutOfRange = true;
9053         memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, dataSize, regNum, isDest, &insn);
9054     } else {
9055         isOutOfRange = false;
9056     }
9057     return memOpnd;
9058 }
9059 
FreeSpillRegMem(regno_t vrNum)9060 void AArch64CGFunc::FreeSpillRegMem(regno_t vrNum)
9061 {
9062     MemOperand *memOpnd = nullptr;
9063 
9064     auto p = spillRegMemOperands.find(vrNum);
9065     if (p != spillRegMemOperands.end()) {
9066         memOpnd = p->second;
9067     }
9068 
9069     if ((memOpnd == nullptr) && IsVRegNOForPseudoRegister(vrNum)) {
9070         auto pSecond = pRegSpillMemOperands.find(GetPseudoRegIdxFromVirtualRegNO(vrNum));
9071         if (pSecond != pRegSpillMemOperands.end()) {
9072             memOpnd = pSecond->second;
9073         }
9074     }
9075 
9076     if (memOpnd == nullptr) {
9077         DEBUG_ASSERT(false, "free spillreg have no mem");
9078         return;
9079     }
9080 
9081     uint32 size = memOpnd->GetSize();
9082     MapleUnorderedMap<uint32, SpillMemOperandSet *>::iterator iter;
9083     if ((iter = reuseSpillLocMem.find(size)) != reuseSpillLocMem.end()) {
9084         iter->second->Add(*memOpnd);
9085     } else {
9086         reuseSpillLocMem[size] = memPool->New<SpillMemOperandSet>(*GetFuncScopeAllocator());
9087         reuseSpillLocMem[size]->Add(*memOpnd);
9088     }
9089 }
9090 
GetOrCreatSpillMem(regno_t vrNum,uint32 memSize)9091 MemOperand *AArch64CGFunc::GetOrCreatSpillMem(regno_t vrNum, uint32 memSize)
9092 {
9093     /* NOTES: must used in RA, not used in other place. */
9094     if (IsVRegNOForPseudoRegister(vrNum)) {
9095         auto p = pRegSpillMemOperands.find(GetPseudoRegIdxFromVirtualRegNO(vrNum));
9096         if (p != pRegSpillMemOperands.end()) {
9097             return p->second;
9098         }
9099     }
9100 
9101     auto p = spillRegMemOperands.find(vrNum);
9102     if (p == spillRegMemOperands.end()) {
9103         if (vrNum >= vReg.VRegTableSize()) {
9104             CHECK_FATAL(false, "index out of range in AArch64CGFunc::FreeSpillRegMem");
9105         }
9106         uint32 memBitSize = (memSize <= k32BitSize) ? k32BitSize : (memSize <= k64BitSize) ? k64BitSize : k128BitSize;
9107         auto it = reuseSpillLocMem.find(memBitSize);
9108         if (it != reuseSpillLocMem.end()) {
9109             MemOperand *memOpnd = it->second->GetOne();
9110             if (memOpnd != nullptr) {
9111                 (void)spillRegMemOperands.emplace(std::pair<regno_t, MemOperand *>(vrNum, memOpnd));
9112                 return memOpnd;
9113             }
9114         }
9115 
9116         RegOperand &baseOpnd = GetOrCreateStackBaseRegOperand();
9117         int64 offset = GetOrCreatSpillRegLocation(vrNum, memBitSize / kBitsPerByte);
9118         MemOperand *memOpnd = nullptr;
9119         OfstOperand *offsetOpnd = &CreateOfstOpnd(static_cast<uint64>(offset), k64BitSize);
9120         memOpnd = CreateMemOperand(MemOperand::kAddrModeBOi, memBitSize, baseOpnd, nullptr, offsetOpnd, nullptr);
9121         (void)spillRegMemOperands.emplace(std::pair<regno_t, MemOperand *>(vrNum, memOpnd));
9122         return memOpnd;
9123     } else {
9124         return p->second;
9125     }
9126 }
9127 
GetPseudoRegisterSpillMemoryOperand(PregIdx i)9128 MemOperand *AArch64CGFunc::GetPseudoRegisterSpillMemoryOperand(PregIdx i)
9129 {
9130     MapleUnorderedMap<PregIdx, MemOperand *>::iterator p;
9131     if (GetCG()->GetOptimizeLevel() == CGOptions::kLevel0) {
9132         p = pRegSpillMemOperands.end();
9133     } else {
9134         p = pRegSpillMemOperands.find(i);
9135     }
9136     if (p != pRegSpillMemOperands.end()) {
9137         return p->second;
9138     }
9139     int64 offset = GetPseudoRegisterSpillLocation(i);
9140     MIRPreg *preg = GetFunction().GetPregTab()->PregFromPregIdx(i);
9141     uint32 bitLen = GetPrimTypeSize(preg->GetPrimType()) * kBitsPerByte;
9142     RegOperand &base = GetOrCreateFramePointerRegOperand();
9143 
9144     OfstOperand &ofstOpnd = GetOrCreateOfstOpnd(static_cast<uint64>(offset), k32BitSize);
9145     MemOperand &memOpnd = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, bitLen, &base, nullptr, &ofstOpnd, nullptr);
9146     if (IsImmediateOffsetOutOfRange(memOpnd, bitLen)) {
9147         MemOperand &newMemOpnd = SplitOffsetWithAddInstruction(memOpnd, bitLen);
9148         (void)pRegSpillMemOperands.emplace(std::pair<PregIdx, MemOperand *>(i, &newMemOpnd));
9149         return &newMemOpnd;
9150     }
9151     (void)pRegSpillMemOperands.emplace(std::pair<PregIdx, MemOperand *>(i, &memOpnd));
9152     return &memOpnd;
9153 }
9154 
GetPseudoRegFromVirtualRegNO(const regno_t vRegNO,bool afterSSA) const9155 MIRPreg *AArch64CGFunc::GetPseudoRegFromVirtualRegNO(const regno_t vRegNO, bool afterSSA) const
9156 {
9157     PregIdx pri = afterSSA ? VRegNOToPRegIdx(vRegNO) : GetPseudoRegIdxFromVirtualRegNO(vRegNO);
9158     if (pri == -1)
9159         return nullptr;
9160     return GetFunction().GetPregTab()->PregFromPregIdx(pri);
9161 }
9162 
9163 /* Get the number of return register of current function. */
GetReturnRegisterNumber()9164 AArch64reg AArch64CGFunc::GetReturnRegisterNumber()
9165 {
9166     CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind());
9167     CCLocInfo retMech;
9168     retLocator.LocateRetVal(*(GetFunction().GetReturnType()), retMech);
9169     if (retMech.GetRegCount() > 0) {
9170         return static_cast<AArch64reg>(retMech.GetReg0());
9171     }
9172     return kRinvalid;
9173 }
9174 
CanLazyBinding(const Insn & ldrInsn) const9175 bool AArch64CGFunc::CanLazyBinding(const Insn &ldrInsn) const
9176 {
9177     Operand &memOpnd = ldrInsn.GetOperand(1);
9178     auto &aarchMemOpnd = static_cast<MemOperand &>(memOpnd);
9179     if (aarchMemOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li) {
9180         return false;
9181     }
9182 
9183     const MIRSymbol *sym = aarchMemOpnd.GetSymbol();
9184     CHECK_FATAL(sym != nullptr, "sym can't be nullptr");
9185     if (sym->IsMuidFuncDefTab() || sym->IsMuidFuncUndefTab() || sym->IsMuidDataDefTab() || sym->IsMuidDataUndefTab() ||
9186         (sym->IsReflectionClassInfo() && !sym->IsReflectionArrayClassInfo())) {
9187         return true;
9188     }
9189 
9190     return false;
9191 }
9192 
9193 /*
9194  *  add reg, reg, __PTR_C_STR_...
9195  *  ldr reg1, [reg]
9196  *  =>
9197  *  ldr reg1, [reg, #:lo12:__Ptr_C_STR_...]
9198  */
ConvertAdrpl12LdrToLdr()9199 void AArch64CGFunc::ConvertAdrpl12LdrToLdr()
9200 {
9201     FOR_ALL_BB(bb, this)
9202     {
9203         FOR_BB_INSNS_SAFE(insn, bb, nextInsn)
9204         {
9205             nextInsn = insn->GetNextMachineInsn();
9206             if (nextInsn == nullptr) {
9207                 break;
9208             }
9209             if (!insn->IsMachineInstruction()) {
9210                 continue;
9211             }
9212             /* check first insn */
9213             MOperator thisMop = insn->GetMachineOpcode();
9214             if (thisMop != MOP_xadrpl12) {
9215                 continue;
9216             }
9217             /* check second insn */
9218             MOperator nextMop = nextInsn->GetMachineOpcode();
9219             if (!(((nextMop >= MOP_wldrsb) && (nextMop <= MOP_dldp)) ||
9220                   ((nextMop >= MOP_wstrb) && (nextMop <= MOP_dstp)))) {
9221                 continue;
9222             }
9223 
9224             /* Check if base register of nextInsn and the dest operand of insn are identical. */
9225             MemOperand *memOpnd = static_cast<MemOperand *>(nextInsn->GetMemOpnd());
9226             CHECK_FATAL(memOpnd != nullptr, "memOpnd can't be nullptr");
9227 
9228             /* Only for AddrMode_B_OI addressing mode. */
9229             if (memOpnd->GetAddrMode() != MemOperand::kAddrModeBOi) {
9230                 continue;
9231             }
9232 
9233             /* Only for intact memory addressing. */
9234             if (!memOpnd->IsIntactIndexed()) {
9235                 continue;
9236             }
9237 
9238             auto &regOpnd = static_cast<RegOperand &>(insn->GetOperand(0));
9239 
9240             /* Check if dest operand of insn is idential with base register of nextInsn. */
9241             RegOperand *baseReg = memOpnd->GetBaseRegister();
9242             CHECK_FATAL(baseReg != nullptr, "baseReg can't be nullptr");
9243             if (baseReg->GetRegisterNumber() != regOpnd.GetRegisterNumber()) {
9244                 continue;
9245             }
9246 
9247             StImmOperand &stImmOpnd = static_cast<StImmOperand &>(insn->GetOperand(kInsnThirdOpnd));
9248             OfstOperand &ofstOpnd = GetOrCreateOfstOpnd(
9249                 static_cast<uint64>(stImmOpnd.GetOffset() + memOpnd->GetOffsetImmediate()->GetOffsetValue()),
9250                 k32BitSize);
9251             RegOperand &newBaseOpnd = static_cast<RegOperand &>(insn->GetOperand(kInsnSecondOpnd));
9252             MemOperand &newMemOpnd = GetOrCreateMemOpnd(MemOperand::kAddrModeLo12Li, memOpnd->GetSize(), &newBaseOpnd,
9253                                                         nullptr, &ofstOpnd, stImmOpnd.GetSymbol());
9254             nextInsn->SetOperand(1, newMemOpnd);
9255             bb->RemoveInsn(*insn);
9256         }
9257     }
9258 }
9259 
9260 /*
9261  * adrp reg1, __muid_func_undef_tab..
9262  * ldr reg2, [reg1, #:lo12:__muid_func_undef_tab..]
9263  * =>
9264  * intrinsic_adrp_ldr reg2, __muid_func_undef_tab...
9265  */
ConvertAdrpLdrToIntrisic()9266 void AArch64CGFunc::ConvertAdrpLdrToIntrisic()
9267 {
9268     FOR_ALL_BB(bb, this)
9269     {
9270         FOR_BB_INSNS_SAFE(insn, bb, nextInsn)
9271         {
9272             nextInsn = insn->GetNextMachineInsn();
9273             if (nextInsn == nullptr) {
9274                 break;
9275             }
9276             if (!insn->IsMachineInstruction()) {
9277                 continue;
9278             }
9279 
9280             MOperator firstMop = insn->GetMachineOpcode();
9281             MOperator secondMop = nextInsn->GetMachineOpcode();
9282             if (!((firstMop == MOP_xadrp) && ((secondMop == MOP_wldr) || (secondMop == MOP_xldr)))) {
9283                 continue;
9284             }
9285 
9286             if (CanLazyBinding(*nextInsn)) {
9287                 bb->ReplaceInsn(
9288                     *insn, GetInsnBuilder()->BuildInsn(MOP_adrp_ldr, nextInsn->GetOperand(0), insn->GetOperand(1)));
9289                 bb->RemoveInsn(*nextInsn);
9290             }
9291         }
9292     }
9293 }
9294 
ProcessLazyBinding()9295 void AArch64CGFunc::ProcessLazyBinding()
9296 {
9297     ConvertAdrpl12LdrToLdr();
9298     ConvertAdrpLdrToIntrisic();
9299 }
9300 
9301 /*
9302  * Generate global long call
9303  *  adrp  VRx, symbol
9304  *  ldr VRx, [VRx, #:lo12:symbol]
9305  *  blr VRx
9306  *
9307  * Input:
9308  *  insn       : insert new instruction after the 'insn'
9309  *  func       : the symbol of the function need to be called
9310  *  srcOpnds   : list operand of the function need to be called
9311  *  isCleanCall: when generate clean call insn, set isCleanCall as true
9312  * Return: the 'blr' instruction
9313  */
GenerateGlobalLongCallAfterInsn(const MIRSymbol & func,ListOperand & srcOpnds)9314 Insn &AArch64CGFunc::GenerateGlobalLongCallAfterInsn(const MIRSymbol &func, ListOperand &srcOpnds)
9315 {
9316     MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(func.GetStIdx());
9317     symbol->SetStorageClass(kScGlobal);
9318     RegOperand &tmpReg = CreateRegisterOperandOfType(PTY_u64);
9319     StImmOperand &stOpnd = CreateStImmOperand(*symbol, 0, 0);
9320     OfstOperand &offsetOpnd = CreateOfstOpnd(*symbol, 0);
9321     Insn &adrpInsn = GetInsnBuilder()->BuildInsn(MOP_xadrp, tmpReg, stOpnd);
9322     GetCurBB()->AppendInsn(adrpInsn);
9323     MemOperand &memOrd = GetOrCreateMemOpnd(MemOperand::kAddrModeLo12Li, GetPointerSize() * kBitsPerByte,
9324                                             static_cast<RegOperand *>(&tmpReg), nullptr, &offsetOpnd, symbol);
9325     Insn &ldrInsn = GetInsnBuilder()->BuildInsn(memOrd.GetSize() == k64BitSize ? MOP_xldr : MOP_wldr, tmpReg, memOrd);
9326     GetCurBB()->AppendInsn(ldrInsn);
9327 
9328     Insn &callInsn = GetInsnBuilder()->BuildInsn(MOP_xblr, tmpReg, srcOpnds);
9329     GetCurBB()->AppendInsn(callInsn);
9330     GetCurBB()->SetHasCall();
9331     return callInsn;
9332 }
9333 
9334 /*
9335  * Generate local long call
9336  *  adrp  VRx, symbol
9337  *  add VRx, VRx, #:lo12:symbol
9338  *  blr VRx
9339  *
9340  * Input:
9341  *  insn       : insert new instruction after the 'insn'
9342  *  func       : the symbol of the function need to be called
9343  *  srcOpnds   : list operand of the function need to be called
9344  *  isCleanCall: when generate clean call insn, set isCleanCall as true
9345  * Return: the 'blr' instruction
9346  */
GenerateLocalLongCallAfterInsn(const MIRSymbol & func,ListOperand & srcOpnds)9347 Insn &AArch64CGFunc::GenerateLocalLongCallAfterInsn(const MIRSymbol &func, ListOperand &srcOpnds)
9348 {
9349     RegOperand &tmpReg = CreateRegisterOperandOfType(PTY_u64);
9350     StImmOperand &stOpnd = CreateStImmOperand(func, 0, 0);
9351     Insn &adrpInsn = GetInsnBuilder()->BuildInsn(MOP_xadrp, tmpReg, stOpnd);
9352     GetCurBB()->AppendInsn(adrpInsn);
9353     Insn &addInsn = GetInsnBuilder()->BuildInsn(MOP_xadrpl12, tmpReg, tmpReg, stOpnd);
9354     GetCurBB()->AppendInsn(addInsn);
9355     Insn *callInsn = &GetInsnBuilder()->BuildInsn(MOP_xblr, tmpReg, srcOpnds);
9356     GetCurBB()->AppendInsn(*callInsn);
9357     GetCurBB()->SetHasCall();
9358     return *callInsn;
9359 }
9360 
AppendCall(const MIRSymbol & sym,ListOperand & srcOpnds)9361 Insn &AArch64CGFunc::AppendCall(const MIRSymbol &sym, ListOperand &srcOpnds)
9362 {
9363     Insn *callInsn = nullptr;
9364     if (CGOptions::IsLongCalls()) {
9365         MIRFunction *mirFunc = sym.GetFunction();
9366         if (IsDuplicateAsmList(sym) || (mirFunc && mirFunc->GetAttr(FUNCATTR_local))) {
9367             callInsn = &GenerateLocalLongCallAfterInsn(sym, srcOpnds);
9368         } else {
9369             callInsn = &GenerateGlobalLongCallAfterInsn(sym, srcOpnds);
9370         }
9371     } else {
9372         Operand &targetOpnd = GetOrCreateFuncNameOpnd(sym);
9373         callInsn = &GetInsnBuilder()->BuildInsn(MOP_xbl, targetOpnd, srcOpnds);
9374         GetCurBB()->AppendInsn(*callInsn);
9375         GetCurBB()->SetHasCall();
9376     }
9377     return *callInsn;
9378 }
9379 
IsDuplicateAsmList(const MIRSymbol & sym) const9380 bool AArch64CGFunc::IsDuplicateAsmList(const MIRSymbol &sym) const
9381 {
9382     if (CGOptions::IsDuplicateAsmFileEmpty()) {
9383         return false;
9384     }
9385 
9386     const std::string &name = sym.GetName();
9387     if ((name == "strlen") || (name == "strncmp") || (name == "memcpy") || (name == "memmove") || (name == "strcmp") ||
9388         (name == "memcmp") || (name == "memcmpMpl")) {
9389         return true;
9390     }
9391     return false;
9392 }
9393 
SelectMPLProfCounterInc(const IntrinsiccallNode & intrnNode)9394 void AArch64CGFunc::SelectMPLProfCounterInc(const IntrinsiccallNode &intrnNode)
9395 {
9396     if (Options::profileGen) {
9397         DEBUG_ASSERT(intrnNode.NumOpnds() == 1, "must be 1 operand");
9398         BaseNode *arg1 = intrnNode.Opnd(0);
9399         DEBUG_ASSERT(arg1 != nullptr, "nullptr check");
9400         regno_t vRegNO1 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
9401         RegOperand &vReg1 = CreateVirtualRegisterOperand(vRegNO1);
9402         vReg1.SetRegNotBBLocal();
9403         static const MIRSymbol *bbProfileTab = nullptr;
9404 
9405         // Ref: MeProfGen::InstrumentFunc on ctrTbl namiLogicalShiftLeftOperandng
9406         std::string ctrTblName = namemangler::kprefixProfCtrTbl + GetMirModule().GetFileName() + "_" + GetName();
9407         std::replace(ctrTblName.begin(), ctrTblName.end(), '.', '_');
9408         std::replace(ctrTblName.begin(), ctrTblName.end(), '-', '_');
9409         std::replace(ctrTblName.begin(), ctrTblName.end(), '/', '_');
9410 
9411         if (!bbProfileTab || bbProfileTab->GetName() != ctrTblName) {
9412             bbProfileTab = GetMirModule().GetMIRBuilder()->GetGlobalDecl(ctrTblName);
9413             CHECK_FATAL(bbProfileTab != nullptr, "expect counter table");
9414         }
9415 
9416         ConstvalNode *constvalNode = static_cast<ConstvalNode *>(arg1);
9417         MIRConst *mirConst = constvalNode->GetConstVal();
9418         DEBUG_ASSERT(mirConst != nullptr, "nullptr check");
9419         CHECK_FATAL(mirConst->GetKind() == kConstInt, "expect MIRIntConst type");
9420         MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(mirConst);
9421         int64 offset = static_cast<int64>(GetPrimTypeSize(PTY_u64)) * mirIntConst->GetExtValue();
9422 
9423         if (!CGOptions::IsQuiet()) {
9424             maple::LogInfo::MapleLogger(kLlInfo) << "At counter table offset: " << offset << std::endl;
9425         }
9426         MemOperand *memOpnd = &GetOrCreateMemOpnd(*bbProfileTab, offset, k64BitSize);
9427         if (IsImmediateOffsetOutOfRange(*memOpnd, k64BitSize)) {
9428             memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, k64BitSize);
9429         }
9430         Operand *reg = &SelectCopy(*memOpnd, PTY_u64, PTY_u64);
9431         ImmOperand &one = CreateImmOperand(1, k64BitSize, false);
9432         SelectAdd(*reg, *reg, one, PTY_u64);
9433         SelectCopy(*memOpnd, PTY_u64, *reg, PTY_u64);
9434         return;
9435     }
9436 
9437     DEBUG_ASSERT(intrnNode.NumOpnds() == 1, "must be 1 operand");
9438     BaseNode *arg1 = intrnNode.Opnd(0);
9439     DEBUG_ASSERT(arg1 != nullptr, "nullptr check");
9440     regno_t vRegNO1 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
9441     RegOperand &vReg1 = CreateVirtualRegisterOperand(vRegNO1);
9442     vReg1.SetRegNotBBLocal();
9443     static const MIRSymbol *bbProfileTab = nullptr;
9444     if (!bbProfileTab) {
9445         std::string bbProfileName = namemangler::kBBProfileTabPrefixStr + GetMirModule().GetFileNameAsPostfix();
9446         bbProfileTab = GetMirModule().GetMIRBuilder()->GetGlobalDecl(bbProfileName);
9447         CHECK_FATAL(bbProfileTab != nullptr, "expect bb profile tab");
9448     }
9449     ConstvalNode *constvalNode = static_cast<ConstvalNode *>(arg1);
9450     MIRConst *mirConst = constvalNode->GetConstVal();
9451     DEBUG_ASSERT(mirConst != nullptr, "nullptr check");
9452     CHECK_FATAL(mirConst->GetKind() == kConstInt, "expect MIRIntConst type");
9453     MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(mirConst);
9454     int64 idx = static_cast<int64>(GetPrimTypeSize(PTY_u32)) * mirIntConst->GetExtValue();
9455     if (!CGOptions::IsQuiet()) {
9456         maple::LogInfo::MapleLogger(kLlErr) << "Id index " << idx << std::endl;
9457     }
9458     StImmOperand &stOpnd = CreateStImmOperand(*bbProfileTab, idx, 0);
9459     Insn &newInsn = GetInsnBuilder()->BuildInsn(MOP_counter, vReg1, stOpnd);
9460     newInsn.SetDoNotRemove(true);
9461     GetCurBB()->AppendInsn(newInsn);
9462 }
9463 
SelectMPLClinitCheck(const IntrinsiccallNode & intrnNode)9464 void AArch64CGFunc::SelectMPLClinitCheck(const IntrinsiccallNode &intrnNode)
9465 {
9466     DEBUG_ASSERT(intrnNode.NumOpnds() == 1, "must be 1 operand");
9467     BaseNode *arg = intrnNode.Opnd(0);
9468     Operand *stOpnd = nullptr;
9469     bool bClinitSeperate = false;
9470     DEBUG_ASSERT(CGOptions::IsPIC(), "must be doPIC");
9471     if (arg->GetOpCode() == OP_addrof) {
9472         AddrofNode *addrof = static_cast<AddrofNode *>(arg);
9473         MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(addrof->GetStIdx());
9474         DEBUG_ASSERT(symbol->GetName().find(CLASSINFO_PREFIX_STR) == 0, "must be a symbol with __classinfo__");
9475 
9476         if (!symbol->IsMuidDataUndefTab()) {
9477             std::string ptrName = namemangler::kPtrPrefixStr + symbol->GetName();
9478             MIRType *ptrType = GlobalTables::GetTypeTable().GetPtr();
9479             symbol = GetMirModule().GetMIRBuilder()->GetOrCreateGlobalDecl(ptrName, *ptrType);
9480             bClinitSeperate = true;
9481             symbol->SetStorageClass(kScFstatic);
9482         }
9483         stOpnd = &CreateStImmOperand(*symbol, 0, 0);
9484     } else {
9485         arg = arg->Opnd(0);
9486         BaseNode *arg0 = arg->Opnd(0);
9487         BaseNode *arg1 = arg->Opnd(1);
9488         DEBUG_ASSERT(arg0 != nullptr, "nullptr check");
9489         DEBUG_ASSERT(arg1 != nullptr, "nullptr check");
9490         DEBUG_ASSERT(arg0->GetOpCode() == OP_addrof, "expect the operand to be addrof");
9491         AddrofNode *addrof = static_cast<AddrofNode *>(arg0);
9492         MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(addrof->GetStIdx());
9493         DEBUG_ASSERT(addrof->GetFieldID() == 0, "For debug SelectMPLClinitCheck.");
9494         ConstvalNode *constvalNode = static_cast<ConstvalNode *>(arg1);
9495         MIRConst *mirConst = constvalNode->GetConstVal();
9496         DEBUG_ASSERT(mirConst != nullptr, "nullptr check");
9497         CHECK_FATAL(mirConst->GetKind() == kConstInt, "expect MIRIntConst type");
9498         MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(mirConst);
9499         stOpnd = &CreateStImmOperand(*symbol, mirIntConst->GetExtValue(), 0);
9500     }
9501 
9502     regno_t vRegNO2 = NewVReg(GetRegTyFromPrimTy(PTY_a64), GetPrimTypeSize(PTY_a64));
9503     RegOperand &vReg2 = CreateVirtualRegisterOperand(vRegNO2);
9504     vReg2.SetRegNotBBLocal();
9505     if (bClinitSeperate) {
9506         /* Seperate MOP_clinit to MOP_adrp_ldr + MOP_clinit_tail. */
9507         Insn &newInsn = GetInsnBuilder()->BuildInsn(MOP_adrp_ldr, vReg2, *stOpnd);
9508         GetCurBB()->AppendInsn(newInsn);
9509         newInsn.SetDoNotRemove(true);
9510         Insn &insn = GetInsnBuilder()->BuildInsn(MOP_clinit_tail, vReg2);
9511         insn.SetDoNotRemove(true);
9512         GetCurBB()->AppendInsn(insn);
9513     } else {
9514         Insn &newInsn = GetInsnBuilder()->BuildInsn(MOP_clinit, vReg2, *stOpnd);
9515         GetCurBB()->AppendInsn(newInsn);
9516     }
9517 }
GenCVaStartIntrin(RegOperand & opnd,uint32 stkSize)9518 void AArch64CGFunc::GenCVaStartIntrin(RegOperand &opnd, uint32 stkSize)
9519 {
9520     /* FPLR only pushed in regalloc() after intrin function */
9521     Operand &stkOpnd = GetOrCreatePhysicalRegisterOperand(RFP, k64BitSize, kRegTyInt);
9522 
9523     /* __stack */
9524     ImmOperand *offsOpnd;
9525     int64 coldToStk = static_cast<int64>(static_cast<AArch64MemLayout *>(GetMemlayout())->GetSizeOfColdToStk());
9526     if (GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) {
9527         // unvary reset StackFrameSize
9528         // unvary to stk bot = coldToStk
9529         offsOpnd = &CreateImmOperand(coldToStk, k64BitSize, true, kUnAdjustVary); /* isvary reset StackFrameSize */
9530     } else {
9531         offsOpnd = &CreateImmOperand(0, k64BitSize, true);
9532     }
9533     ImmOperand *offsOpnd2 = &CreateImmOperand(stkSize, k64BitSize, false);
9534     RegOperand &vReg = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, GetPrimTypeSize(GetLoweredPtrType())));
9535     if (stkSize) {
9536         SelectAdd(vReg, *offsOpnd, *offsOpnd2, GetLoweredPtrType());
9537         SelectAdd(vReg, stkOpnd, vReg, GetLoweredPtrType());
9538     } else {
9539         SelectAdd(vReg, stkOpnd, *offsOpnd, GetLoweredPtrType()); /* stack pointer */
9540     }
9541     OfstOperand *offOpnd = &GetOrCreateOfstOpnd(0, k64BitSize); /* va_list ptr */
9542     /* mem operand in va_list struct (lhs) */
9543     MemOperand *strOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, &opnd, nullptr, offOpnd,
9544                                               static_cast<MIRSymbol *>(nullptr));
9545     GetCurBB()->AppendInsn(
9546         GetInsnBuilder()->BuildInsn(vReg.GetSize() == k64BitSize ? MOP_xstr : MOP_wstr, vReg, *strOpnd));
9547 
9548     /* __gr_top   ; it's the same as __stack before the 1st va_arg */
9549     if (CGOptions::IsArm64ilp32()) {
9550         offOpnd = &GetOrCreateOfstOpnd(GetPointerSize(), k64BitSize);
9551     } else {
9552         offOpnd = &GetOrCreateOfstOpnd(k8BitSize, k64BitSize);
9553     }
9554     strOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, &opnd, nullptr, offOpnd,
9555                                   static_cast<MIRSymbol *>(nullptr));
9556     SelectAdd(vReg, stkOpnd, *offsOpnd, GetLoweredPtrType());
9557     GetCurBB()->AppendInsn(
9558         GetInsnBuilder()->BuildInsn(vReg.GetSize() == k64BitSize ? MOP_xstr : MOP_wstr, vReg, *strOpnd));
9559 
9560     /* __vr_top */
9561     int32 grAreaSize = static_cast<int32>(static_cast<AArch64MemLayout *>(GetMemlayout())->GetSizeOfGRSaveArea());
9562     if (CGOptions::IsArm64ilp32()) {
9563         offsOpnd2 = &CreateImmOperand(static_cast<int64>(RoundUp(static_cast<uint64>(grAreaSize), k8ByteSize << 1)),
9564                                       k64BitSize, false);
9565     } else {
9566         offsOpnd2 = &CreateImmOperand(
9567             static_cast<int64>(RoundUp(static_cast<uint64>(grAreaSize), GetPointerSize() << 1)), k64BitSize, false);
9568     }
9569     SelectSub(vReg, *offsOpnd, *offsOpnd2, GetLoweredPtrType()); /* if 1st opnd is register => sub */
9570     SelectAdd(vReg, stkOpnd, vReg, GetLoweredPtrType());
9571     offOpnd = &GetOrCreateOfstOpnd(GetPointerSize() << 1, k64BitSize);
9572     strOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, &opnd, nullptr, offOpnd,
9573                                   static_cast<MIRSymbol *>(nullptr));
9574     GetCurBB()->AppendInsn(
9575         GetInsnBuilder()->BuildInsn(vReg.GetSize() == k64BitSize ? MOP_xstr : MOP_wstr, vReg, *strOpnd));
9576 
9577     /* __gr_offs */
9578     int32 offs = 0 - grAreaSize;
9579     offsOpnd = &CreateImmOperand(offs, k32BitSize, false);
9580     RegOperand *tmpReg = &CreateRegisterOperandOfType(PTY_i32); /* offs value to be assigned (rhs) */
9581     SelectCopyImm(*tmpReg, *offsOpnd, PTY_i32);
9582     // write __gr_offs : offset from gr_top to next GP register arg
9583     // accroding to typedef struct va_list
9584     // the field offset of __gr_offs is 3 pointer from beginning
9585     offOpnd = &GetOrCreateOfstOpnd(GetPointerSize() * 3, k32BitSize);
9586     strOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k32BitSize, &opnd, nullptr, offOpnd,
9587                                   static_cast<MIRSymbol *>(nullptr));
9588     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wstr, *tmpReg, *strOpnd));
9589 
9590     /* __vr_offs */
9591     offs =
9592         static_cast<int32>(UINT32_MAX - (static_cast<AArch64MemLayout *>(GetMemlayout())->GetSizeOfVRSaveArea() - 1UL));
9593     offsOpnd = &CreateImmOperand(offs, k32BitSize, false);
9594     tmpReg = &CreateRegisterOperandOfType(PTY_i32);
9595     SelectCopyImm(*tmpReg, *offsOpnd, PTY_i32);
9596     // write __vr_offs : offset from vr_top to next FP/SIMD register arg
9597     // accroding to typedef struct va_list
9598     // the field offset of __vr_offs is 3 pointer + sizeof(int) from beginning
9599     offOpnd = &GetOrCreateOfstOpnd((GetPointerSize() * 3 + sizeof(int32)), k32BitSize);
9600     strOpnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k32BitSize, &opnd, nullptr, offOpnd,
9601                                   static_cast<MIRSymbol *>(nullptr));
9602     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wstr, *tmpReg, *strOpnd));
9603 }
9604 
SelectCVaStart(const IntrinsiccallNode & intrnNode)9605 void AArch64CGFunc::SelectCVaStart(const IntrinsiccallNode &intrnNode)
9606 {
9607     DEBUG_ASSERT(intrnNode.NumOpnds() == 2, "must be 2 operands");  // must be 2 operands
9608     /* 2 operands, but only 1 needed. Don't need to emit code for second operand
9609      *
9610      * va_list is a passed struct with an address, load its address
9611      */
9612     isIntrnCallForC = true;
9613     BaseNode *argExpr = intrnNode.Opnd(0);
9614     Operand *opnd = HandleExpr(intrnNode, *argExpr);
9615     RegOperand &opnd0 = LoadIntoRegister(*opnd, GetLoweredPtrType()); /* first argument of intrinsic */
9616 
9617     /* Find beginning of unnamed arg on stack.
9618      * Ex. void foo(int i1, int i2, ... int i8, struct S r, struct S s, ...)
9619      *     where struct S has size 32, address of r and s are on stack but they are named.
9620      */
9621     AArch64CallConvImpl parmLocator(GetBecommon());
9622     CCLocInfo pLoc;
9623     uint32 stkSize = 0;
9624     uint32 inReg = 0;
9625     for (uint32 i = 0; i < GetFunction().GetFormalCount(); i++) {
9626         MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetFunction().GetNthParamTyIdx(i));
9627         parmLocator.LocateNextParm(*ty, pLoc);
9628         if (pLoc.reg0 == kRinvalid) { /* on stack */
9629             stkSize = static_cast<uint32_t>(pLoc.memOffset + pLoc.memSize);
9630         } else {
9631             inReg++;
9632         }
9633     }
9634     if (GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) {
9635         stkSize += (inReg * k8ByteSize);
9636     }
9637     if (CGOptions::IsArm64ilp32()) {
9638         stkSize = static_cast<uint32>(RoundUp(stkSize, k8ByteSize));
9639     } else {
9640         stkSize = static_cast<uint32>(RoundUp(stkSize, GetPointerSize()));
9641     }
9642 
9643     GenCVaStartIntrin(opnd0, stkSize);
9644 
9645     return;
9646 }
9647 
9648 // output
9649 // add_with_overflow/ sub_with_overflow:
9650 //    w1: parm1
9651 //    w2: parm2
9652 //    adds/subs w0, w1, w2
9653 //    cset w3, vs
9654 
9655 // mul_with_overflow:
9656 //    w1: parm1
9657 //    w2: parm2
9658 //    smull x0, w0, w1
9659 //    cmp   x0, w0, sxtw
9660 //    cset  w4, ne
SelectOverFlowCall(const IntrinsiccallNode & intrnNode)9661 void AArch64CGFunc::SelectOverFlowCall(const IntrinsiccallNode &intrnNode)
9662 {
9663     DEBUG_ASSERT(intrnNode.NumOpnds() == 2, "must be 2 operands");  // must be 2 operands
9664     MIRIntrinsicID intrinsic = intrnNode.GetIntrinsic();
9665     PrimType type = intrnNode.Opnd(0)->GetPrimType();
9666     PrimType type2 = intrnNode.Opnd(1)->GetPrimType();
9667     CHECK_FATAL(type == PTY_i32 || type == PTY_u32, "only support i32 or u32 here");
9668     CHECK_FATAL(type2 == PTY_i32 || type2 == PTY_u32, "only support i32 or u32 here");
9669     // deal with parms
9670     RegOperand &opnd0 = LoadIntoRegister(*HandleExpr(intrnNode, *intrnNode.Opnd(0)),
9671                                          intrnNode.Opnd(0)->GetPrimType()); /* first argument of intrinsic */
9672     RegOperand &opnd1 = LoadIntoRegister(*HandleExpr(intrnNode, *intrnNode.Opnd(1)),
9673                                          intrnNode.Opnd(1)->GetPrimType()); /* first argument of intrinsic */
9674     RegOperand &resReg = CreateRegisterOperandOfType(type);
9675     RegOperand &resReg2 = CreateRegisterOperandOfType(PTY_u8);
9676     Operand &rflag = GetOrCreateRflag();
9677     // arith operation with set flag
9678     if (intrinsic == INTRN_ADD_WITH_OVERFLOW) {
9679         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_waddsrrr, rflag, resReg, opnd0, opnd1));
9680         SelectAArch64CSet(resReg2, GetCondOperand(CC_VS), false);
9681     } else if (intrinsic == INTRN_SUB_WITH_OVERFLOW) {
9682         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wsubsrrr, rflag, resReg, opnd0, opnd1));
9683         SelectAArch64CSet(resReg2, GetCondOperand(CC_VS), false);
9684     } else if (intrinsic == INTRN_MUL_WITH_OVERFLOW) {
9685         // smull
9686         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xsmullrrr, resReg, opnd0, opnd1));
9687         Operand &sxtw = CreateExtendShiftOperand(ExtendShiftOperand::kSXTW, 0, k3BitSize);
9688         Insn &cmpInsn = GetInsnBuilder()->BuildInsn(MOP_xwcmprre, rflag, resReg, resReg, sxtw);
9689         GetCurBB()->AppendInsn(cmpInsn);
9690         SelectAArch64CSet(resReg2, GetCondOperand(CC_NE), false);
9691     } else {
9692         CHECK_FATAL(false, "niy");
9693     }
9694     // store back
9695     auto *retVals = &intrnNode.GetReturnVec();
9696     auto &pair = retVals->at(0);
9697     stIdx2OverflowResult[pair.first] = std::pair<RegOperand *, RegOperand *>(&resReg, &resReg2);
9698     return;
9699 }
9700 
9701 /*
9702  * intrinsiccall C___Atomic_store_N(ptr, val, memorder))
9703  * ====> *ptr = val
9704  * let ptr -> x0
9705  * let val -> x1
9706  * implement to asm: str/stlr x1, [x0]
9707  * a store-release would replace str if memorder is not 0
9708  */
SelectCAtomicStoreN(const IntrinsiccallNode & intrinsiccallNode)9709 void AArch64CGFunc::SelectCAtomicStoreN(const IntrinsiccallNode &intrinsiccallNode)
9710 {
9711     auto primType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(intrinsiccallNode.GetTyIdx())->GetPrimType();
9712     auto *addr = HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(0));
9713     auto *value = HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(1));
9714     auto *memOrderOpnd = intrinsiccallNode.Opnd(kInsnThirdOpnd);
9715     std::memory_order memOrder = std::memory_order_seq_cst;
9716     if (memOrderOpnd->IsConstval()) {
9717         auto *memOrderConst = static_cast<MIRIntConst *>(static_cast<ConstvalNode *>(memOrderOpnd)->GetConstVal());
9718         memOrder = static_cast<std::memory_order>(memOrderConst->GetExtValue());
9719     }
9720     SelectAtomicStore(*value, *addr, primType, PickMemOrder(memOrder, false));
9721 }
9722 
SelectAtomicStore(Operand & srcOpnd,Operand & addrOpnd,PrimType primType,AArch64isa::MemoryOrdering memOrder)9723 void AArch64CGFunc::SelectAtomicStore(Operand &srcOpnd, Operand &addrOpnd, PrimType primType,
9724                                       AArch64isa::MemoryOrdering memOrder)
9725 {
9726     auto &memOpnd = CreateMemOpnd(LoadIntoRegister(addrOpnd, PTY_a64), 0, k64BitSize);
9727     auto mOp = PickStInsn(GetPrimTypeBitSize(primType), primType, memOrder);
9728     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, LoadIntoRegister(srcOpnd, primType), memOpnd));
9729 }
9730 
SelectAddrofThreadLocal(Operand & result,StImmOperand & stImm)9731 void AArch64CGFunc::SelectAddrofThreadLocal(Operand &result, StImmOperand &stImm)
9732 {
9733     if (CGOptions::IsPIC()) {
9734         SelectCTlsGlobalDesc(result, stImm);
9735     } else {
9736         SelectCTlsLocalDesc(result, stImm);
9737     }
9738     if (stImm.GetOffset() > 0) {
9739         auto &immOpnd = CreateImmOperand(stImm.GetOffset(), result.GetSize(), false);
9740         SelectAdd(result, result, immOpnd, PTY_u64);
9741     }
9742 }
9743 
SelectCTlsLocalDesc(Operand & result,StImmOperand & stImm)9744 void AArch64CGFunc::SelectCTlsLocalDesc(Operand &result, StImmOperand &stImm)
9745 {
9746     auto tpidr = &CreateCommentOperand("tpidr_el0");
9747     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_mrs, result, *tpidr));
9748     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_tls_desc_rel, result, result, stImm));
9749 }
9750 
SelectCTlsGlobalDesc(Operand & result,StImmOperand & stImm)9751 void AArch64CGFunc::SelectCTlsGlobalDesc(Operand &result, StImmOperand &stImm)
9752 {
9753     /* according to AArch64 Machine Directives */
9754     auto &r0opnd = GetOrCreatePhysicalRegisterOperand(R0, k64BitSize, GetRegTyFromPrimTy(PTY_u64));
9755     RegOperand *tlsAddr = &CreateRegisterOperandOfType(PTY_u64);
9756     RegOperand *specialFunc = &CreateRegisterOperandOfType(PTY_u64);
9757     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_tls_desc_call, r0opnd, *tlsAddr, stImm));
9758     /* release tls address */
9759     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_pseduo_tls_release, *tlsAddr));
9760     //  mrs xn, tpidr_el0
9761     //  add x0, x0, xn
9762     auto tpidr = &CreateCommentOperand("tpidr_el0");
9763     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_mrs, *specialFunc, *tpidr));
9764     SelectAdd(result, r0opnd, *specialFunc, PTY_u64);
9765 }
9766 
SelectIntrinsicCall(IntrinsiccallNode & intrinsiccallNode)9767 void AArch64CGFunc::SelectIntrinsicCall(IntrinsiccallNode &intrinsiccallNode)
9768 {
9769     MIRIntrinsicID intrinsic = intrinsiccallNode.GetIntrinsic();
9770 
9771     if (GetCG()->GenerateVerboseCG()) {
9772         std::string comment = GetIntrinsicName(intrinsic);
9773         GetCurBB()->AppendInsn(CreateCommentInsn(comment));
9774     }
9775 
9776     /*
9777      * At this moment, we eagerly evaluates all argument expressions.  In theory,
9778      * there could be intrinsics that extract meta-information of variables, such as
9779      * their locations, rather than computing their values.  Applications
9780      * include building stack maps that help runtime libraries to find the values
9781      * of local variables (See @stackmap in LLVM), in which case knowing their
9782      * locations will suffice.
9783      */
9784     if (intrinsic == INTRN_MPL_PROF_COUNTER_INC) { /* special case */
9785         SelectMPLProfCounterInc(intrinsiccallNode);
9786         return;
9787     }
9788     // js
9789     if (intrinsic == INTRN_ADD_WITH_OVERFLOW || intrinsic == INTRN_SUB_WITH_OVERFLOW ||
9790         intrinsic == INTRN_MUL_WITH_OVERFLOW) {
9791         SelectOverFlowCall(intrinsiccallNode);
9792         return;
9793     }
9794     switch (intrinsic) {
9795         case INTRN_C_va_start:
9796             SelectCVaStart(intrinsiccallNode);
9797             return;
9798         case INTRN_C___sync_lock_release_1:
9799             SelectCSyncLockRelease(intrinsiccallNode, PTY_u8);
9800             return;
9801         case INTRN_C___sync_lock_release_2:
9802             SelectCSyncLockRelease(intrinsiccallNode, PTY_u16);
9803             return;
9804         case INTRN_C___sync_lock_release_4:
9805             SelectCSyncLockRelease(intrinsiccallNode, PTY_u32);
9806             return;
9807         case INTRN_C___sync_lock_release_8:
9808             SelectCSyncLockRelease(intrinsiccallNode, PTY_u64);
9809             return;
9810         case INTRN_C___atomic_store_n:
9811             SelectCAtomicStoreN(intrinsiccallNode);
9812             return;
9813         case INTRN_vector_zip_v8u8:
9814         case INTRN_vector_zip_v8i8:
9815         case INTRN_vector_zip_v4u16:
9816         case INTRN_vector_zip_v4i16:
9817         case INTRN_vector_zip_v2u32:
9818         case INTRN_vector_zip_v2i32:
9819             SelectVectorZip(intrinsiccallNode.Opnd(0)->GetPrimType(),
9820                             HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(0)),
9821                             HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(1)));
9822             return;
9823         case INTRN_C_stack_save:
9824             return;
9825         case INTRN_C_stack_restore:
9826             return;
9827         case INTRN_C___builtin_division_exception:
9828             SelectCDIVException();
9829             return;
9830         default:
9831             break;
9832     }
9833     std::vector<Operand *> operands; /* Temporary.  Deallocated on return. */
9834     ListOperand *srcOpnds = CreateListOpnd(*GetFuncScopeAllocator());
9835     for (size_t i = 0; i < intrinsiccallNode.NumOpnds(); i++) {
9836         BaseNode *argExpr = intrinsiccallNode.Opnd(i);
9837         Operand *opnd = HandleExpr(intrinsiccallNode, *argExpr);
9838         operands.emplace_back(opnd);
9839         if (!opnd->IsRegister()) {
9840             opnd = &LoadIntoRegister(*opnd, argExpr->GetPrimType());
9841         }
9842         RegOperand *expRegOpnd = static_cast<RegOperand *>(opnd);
9843         srcOpnds->PushOpnd(*expRegOpnd);
9844     }
9845     CallReturnVector *retVals = &intrinsiccallNode.GetReturnVec();
9846 
9847     switch (intrinsic) {
9848         case INTRN_MPL_ATOMIC_EXCHANGE_PTR: {
9849             BB *origFtBB = GetCurBB()->GetNext();
9850             Operand *loc = operands[kInsnFirstOpnd];
9851             Operand *newVal = operands[kInsnSecondOpnd];
9852             Operand *memOrd = operands[kInsnThirdOpnd];
9853 
9854             MemOrd ord = OperandToMemOrd(*memOrd);
9855             bool isAcquire = MemOrdIsAcquire(ord);
9856             bool isRelease = MemOrdIsRelease(ord);
9857 
9858             const PrimType kValPrimType = PTY_a64;
9859 
9860             RegOperand &locReg = LoadIntoRegister(*loc, PTY_a64);
9861             /* Because there is no live analysis when -O1 */
9862             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
9863                 locReg.SetRegNotBBLocal();
9864             }
9865             MemOperand &locMem = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, &locReg, nullptr,
9866                                                     &GetOrCreateOfstOpnd(0, k32BitSize), nullptr);
9867             RegOperand &newValReg = LoadIntoRegister(*newVal, PTY_a64);
9868             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
9869                 newValReg.SetRegNotBBLocal();
9870             }
9871             GetCurBB()->SetKind(BB::kBBFallthru);
9872 
9873             LabelIdx retryLabIdx = CreateLabeledBB(intrinsiccallNode);
9874 
9875             RegOperand *oldVal = SelectLoadExcl(kValPrimType, locMem, isAcquire);
9876             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
9877                 oldVal->SetRegNotBBLocal();
9878             }
9879             RegOperand *succ = SelectStoreExcl(kValPrimType, locMem, newValReg, isRelease);
9880             if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
9881                 succ->SetRegNotBBLocal();
9882             }
9883 
9884             GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wcbnz, *succ, GetOrCreateLabelOperand(retryLabIdx)));
9885             GetCurBB()->SetKind(BB::kBBIntrinsic);
9886             GetCurBB()->SetNext(origFtBB);
9887 
9888             SaveReturnValueInLocal(*retVals, 0, kValPrimType, *oldVal, intrinsiccallNode);
9889             break;
9890         }
9891         case INTRN_C___atomic_exchange_n: {
9892             Operand *oldVal = SelectCAtomicExchangeN(intrinsiccallNode);
9893             auto primType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(intrinsiccallNode.GetTyIdx())->GetPrimType();
9894             uint32 regSize = GetPrimTypeBitSize(primType);
9895             SelectCopy(GetOrCreatePhysicalRegisterOperand(R0, regSize, kRegTyInt), primType, *oldVal, primType);
9896             break;
9897         }
9898         default: {
9899             CHECK_FATAL(false, "Intrinsic %d: %s not implemented by the AArch64 CG.", intrinsic,
9900                         GetIntrinsicName(intrinsic));
9901             break;
9902         }
9903     }
9904 }
9905 
SelectCclz(IntrinsicopNode & intrnNode)9906 Operand *AArch64CGFunc::SelectCclz(IntrinsicopNode &intrnNode)
9907 {
9908     BaseNode *argexpr = intrnNode.Opnd(0);
9909     PrimType ptype = argexpr->GetPrimType();
9910     Operand *opnd = HandleExpr(intrnNode, *argexpr);
9911     MOperator mop;
9912 
9913     RegOperand &ldDest = CreateRegisterOperandOfType(ptype);
9914     if (opnd->IsMemoryAccessOperand()) {
9915         Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype), ptype), ldDest, *opnd);
9916         GetCurBB()->AppendInsn(insn);
9917         opnd = &ldDest;
9918     } else if (opnd->IsImmediate()) {
9919         SelectCopyImm(ldDest, *static_cast<ImmOperand *>(opnd), ptype);
9920         opnd = &ldDest;
9921     }
9922 
9923     if (GetPrimTypeSize(ptype) == k4ByteSize) {
9924         mop = MOP_wclz;
9925     } else {
9926         mop = MOP_xclz;
9927     }
9928     RegOperand &dst = CreateRegisterOperandOfType(ptype);
9929     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mop, dst, *opnd));
9930     return &dst;
9931 }
9932 
SelectCctz(IntrinsicopNode & intrnNode)9933 Operand *AArch64CGFunc::SelectCctz(IntrinsicopNode &intrnNode)
9934 {
9935     BaseNode *argexpr = intrnNode.Opnd(0);
9936     PrimType ptype = argexpr->GetPrimType();
9937     Operand *opnd = HandleExpr(intrnNode, *argexpr);
9938 
9939     RegOperand &ldDest = CreateRegisterOperandOfType(ptype);
9940     if (opnd->IsMemoryAccessOperand()) {
9941         Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype), ptype), ldDest, *opnd);
9942         GetCurBB()->AppendInsn(insn);
9943         opnd = &ldDest;
9944     } else if (opnd->IsImmediate()) {
9945         SelectCopyImm(ldDest, *static_cast<ImmOperand *>(opnd), ptype);
9946         opnd = &ldDest;
9947     }
9948 
9949     MOperator clzmop;
9950     MOperator rbitmop;
9951     if (GetPrimTypeSize(ptype) == k4ByteSize) {
9952         clzmop = MOP_wclz;
9953         rbitmop = MOP_wrbit;
9954     } else {
9955         clzmop = MOP_xclz;
9956         rbitmop = MOP_xrbit;
9957     }
9958     RegOperand &dst1 = CreateRegisterOperandOfType(ptype);
9959     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(rbitmop, dst1, *opnd));
9960     RegOperand &dst2 = CreateRegisterOperandOfType(ptype);
9961     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(clzmop, dst2, dst1));
9962     return &dst2;
9963 }
9964 
SelectCpopcount(IntrinsicopNode & intrnNode)9965 Operand *AArch64CGFunc::SelectCpopcount(IntrinsicopNode &intrnNode)
9966 {
9967     CHECK_FATAL(false, "%s NIY", intrnNode.GetIntrinDesc().name);
9968     return nullptr;
9969 }
9970 
SelectCparity(IntrinsicopNode & intrnNode)9971 Operand *AArch64CGFunc::SelectCparity(IntrinsicopNode &intrnNode)
9972 {
9973     CHECK_FATAL(false, "%s NIY", intrnNode.GetIntrinDesc().name);
9974     return nullptr;
9975 }
9976 
SelectCclrsb(IntrinsicopNode & intrnNode)9977 Operand *AArch64CGFunc::SelectCclrsb(IntrinsicopNode &intrnNode)
9978 {
9979     BaseNode *argexpr = intrnNode.Opnd(0);
9980     PrimType ptype = argexpr->GetPrimType();
9981     Operand *opnd = HandleExpr(intrnNode, *argexpr);
9982 
9983     RegOperand &ldDest = CreateRegisterOperandOfType(ptype);
9984     if (opnd->IsMemoryAccessOperand()) {
9985         Insn &insn = GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype), ptype), ldDest, *opnd);
9986         GetCurBB()->AppendInsn(insn);
9987         opnd = &ldDest;
9988     } else if (opnd->IsImmediate()) {
9989         SelectCopyImm(ldDest, *static_cast<ImmOperand *>(opnd), ptype);
9990         opnd = &ldDest;
9991     }
9992 
9993     bool is32Bit = (GetPrimTypeSize(ptype) == k4ByteSize);
9994     RegOperand &res = CreateRegisterOperandOfType(ptype);
9995     SelectMvn(res, *opnd, ptype);
9996     SelectAArch64Cmp(*opnd, GetZeroOpnd(is32Bit ? k32BitSize : k64BitSize), true, is32Bit ? k32BitSize : k64BitSize);
9997     SelectAArch64Select(*opnd, res, *opnd, GetCondOperand(CC_LT), true, is32Bit ? k32BitSize : k64BitSize);
9998     MOperator clzmop = (is32Bit ? MOP_wclz : MOP_xclz);
9999     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(clzmop, *opnd, *opnd));
10000     SelectSub(*opnd, *opnd, CreateImmOperand(1, is32Bit ? k32BitSize : k64BitSize, true), ptype);
10001     return opnd;
10002 }
10003 
SelectCisaligned(IntrinsicopNode & intrnNode)10004 Operand *AArch64CGFunc::SelectCisaligned(IntrinsicopNode &intrnNode)
10005 {
10006     BaseNode *argexpr0 = intrnNode.Opnd(0);
10007     PrimType ptype0 = argexpr0->GetPrimType();
10008     Operand *opnd0 = HandleExpr(intrnNode, *argexpr0);
10009 
10010     RegOperand &ldDest0 = CreateRegisterOperandOfType(ptype0);
10011     if (opnd0->IsMemoryAccessOperand()) {
10012         GetCurBB()->AppendInsn(
10013             GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype0), ptype0), ldDest0, *opnd0));
10014         opnd0 = &ldDest0;
10015     } else if (opnd0->IsImmediate()) {
10016         SelectCopyImm(ldDest0, *static_cast<ImmOperand *>(opnd0), ptype0);
10017         opnd0 = &ldDest0;
10018     }
10019 
10020     BaseNode *argexpr1 = intrnNode.Opnd(1);
10021     PrimType ptype1 = argexpr1->GetPrimType();
10022     Operand *opnd1 = HandleExpr(intrnNode, *argexpr1);
10023 
10024     RegOperand &ldDest1 = CreateRegisterOperandOfType(ptype1);
10025     if (opnd1->IsMemoryAccessOperand()) {
10026         GetCurBB()->AppendInsn(
10027             GetInsnBuilder()->BuildInsn(PickLdInsn(GetPrimTypeBitSize(ptype1), ptype1), ldDest1, *opnd1));
10028         opnd1 = &ldDest1;
10029     } else if (opnd1->IsImmediate()) {
10030         SelectCopyImm(ldDest1, *static_cast<ImmOperand *>(opnd1), ptype1);
10031         opnd1 = &ldDest1;
10032     }
10033     // mov w4, #1
10034     RegOperand &reg0 = CreateRegisterOperandOfType(PTY_i32);
10035     SelectCopyImm(reg0, CreateImmOperand(1, k32BitSize, true), PTY_i32);
10036     // sxtw x4, w4
10037     MOperator mOp = MOP_xsxtw64;
10038     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, reg0, reg0));
10039     // sub x3, x3, x4
10040     SelectSub(*opnd1, *opnd1, reg0, ptype1);
10041     // and x2, x2, x3
10042     SelectBand(*opnd0, *opnd0, *opnd1, ptype1);
10043     // mov w3, #0
10044     // sxtw x3, w3
10045     // cmp x2, x3
10046     SelectAArch64Cmp(*opnd0, GetZeroOpnd(k64BitSize), true, k64BitSize);
10047     // cset w2, EQ
10048     SelectAArch64CSet(*opnd0, GetCondOperand(CC_EQ), false);
10049     return opnd0;
10050 }
10051 
SelectArithmeticAndLogical(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType,Opcode op)10052 void AArch64CGFunc::SelectArithmeticAndLogical(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType,
10053                                                Opcode op)
10054 {
10055     switch (op) {
10056         case OP_add:
10057             SelectAdd(resOpnd, opnd0, opnd1, primType);
10058             break;
10059         case OP_sub:
10060             SelectSub(resOpnd, opnd0, opnd1, primType);
10061             break;
10062         case OP_band:
10063             SelectBand(resOpnd, opnd0, opnd1, primType);
10064             break;
10065         case OP_bior:
10066             SelectBior(resOpnd, opnd0, opnd1, primType);
10067             break;
10068         case OP_bxor:
10069             SelectBxor(resOpnd, opnd0, opnd1, primType);
10070             break;
10071         default:
10072             CHECK_FATAL(false, "unconcerned opcode for arithmetical and logical insns");
10073             break;
10074     }
10075 }
10076 
SelectAArch64CSyncFetch(const IntrinsicopNode & intrinopNode,Opcode op,bool fetchBefore)10077 Operand *AArch64CGFunc::SelectAArch64CSyncFetch(const IntrinsicopNode &intrinopNode, Opcode op, bool fetchBefore)
10078 {
10079     auto primType = intrinopNode.GetPrimType();
10080     /* Create BB which includes atomic built_in function */
10081     LabelIdx atomicBBLabIdx = CreateLabel();
10082     BB *atomicBB = CreateNewBB();
10083     atomicBB->SetKind(BB::kBBIf);
10084     atomicBB->SetAtomicBuiltIn();
10085     atomicBB->AddLabel(atomicBBLabIdx);
10086     SetLab2BBMap(static_cast<int32>(atomicBBLabIdx), *atomicBB);
10087     GetCurBB()->AppendBB(*atomicBB);
10088     /* keep variables inside same BB */
10089     if (GetCG()->GetOptimizeLevel() == CGOptions::kLevel0) {
10090         SetCurBB(*atomicBB);
10091     }
10092     /* handle built_in args */
10093     Operand *addrOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnFirstOpnd));
10094     Operand *valueOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnSecondOpnd));
10095     addrOpnd = &LoadIntoRegister(*addrOpnd, intrinopNode.GetNopndAt(kInsnFirstOpnd)->GetPrimType());
10096     valueOpnd = &LoadIntoRegister(*valueOpnd, intrinopNode.GetNopndAt(kInsnSecondOpnd)->GetPrimType());
10097     if (GetCG()->GetOptimizeLevel() != CGOptions::kLevel0) {
10098         SetCurBB(*atomicBB);
10099     }
10100     /* load from pointed address */
10101     auto primTypeP2Size = GetPrimTypeP2Size(primType);
10102     auto *regLoaded = &CreateRegisterOperandOfType(primType);
10103     auto &memOpnd = CreateMemOpnd(*static_cast<RegOperand *>(addrOpnd), 0, GetPrimTypeBitSize(primType));
10104     auto mOpLoad = PickLoadStoreExclInsn(primTypeP2Size, false, false);
10105     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpLoad, *regLoaded, memOpnd));
10106     /* update loaded value */
10107     auto *regOperated = &CreateRegisterOperandOfType(primType);
10108     SelectArithmeticAndLogical(*regOperated, *regLoaded, *valueOpnd, primType, op);
10109     /* store to pointed address */
10110     auto *accessStatus = &CreateRegisterOperandOfType(PTY_u32);
10111     auto mOpStore = PickLoadStoreExclInsn(primTypeP2Size, true, true);
10112     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpStore, *accessStatus, *regOperated, memOpnd));
10113     /* check the exclusive accsess status */
10114     auto &atomicBBOpnd = GetOrCreateLabelOperand(*atomicBB);
10115     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wcbnz, *accessStatus, atomicBBOpnd));
10116 
10117     /* Data Memory Barrier */
10118     BB *nextBB = CreateNewBB();
10119     atomicBB->AppendBB(*nextBB);
10120     SetCurBB(*nextBB);
10121     nextBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ish, AArch64CG::kMd[MOP_dmb_ish]));
10122     return fetchBefore ? regLoaded : regOperated;
10123 }
10124 
SelectCSyncCmpSwap(const IntrinsicopNode & intrinopNode,bool retBool)10125 Operand *AArch64CGFunc::SelectCSyncCmpSwap(const IntrinsicopNode &intrinopNode, bool retBool)
10126 {
10127     PrimType primType = intrinopNode.GetNopndAt(kInsnSecondOpnd)->GetPrimType();
10128     LabelIdx atomicBBLabIdx = CreateLabel();
10129     /* Create BB which includes atomic built_in function */
10130     BB *atomicBB = CreateNewBB();
10131     atomicBB->SetKind(BB::kBBIf);
10132     atomicBB->SetAtomicBuiltIn();
10133     atomicBB->AddLabel(atomicBBLabIdx);
10134     SetLab2BBMap(static_cast<int32>(atomicBBLabIdx), *atomicBB);
10135     GetCurBB()->AppendBB(*atomicBB);
10136     /* keep variables inside same BB in O0 to avoid obtaining parameter value across BB blocks */
10137     if (GetCG()->GetOptimizeLevel() == CGOptions::kLevel0) {
10138         SetCurBB(*atomicBB);
10139     }
10140     /* handle built_in args */
10141     Operand *addrOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnFirstOpnd));
10142     Operand *oldVal = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnSecondOpnd));
10143 
10144     PrimType nodePrimType = intrinopNode.GetPrimType();
10145     uint32 nodePrimTypeSize = GetPrimTypeSize(nodePrimType);
10146     // ensure the value is not changed after loading with extention
10147     if (IsSignedInteger(nodePrimType) && nodePrimTypeSize < k4ByteSize && GetCurBB() &&
10148         GetCurBB()->GetLastMachineInsn() && GetCurBB()->GetLastMachineInsn()->IsLoad()) {
10149         int64 maxIntVal = nodePrimTypeSize == k1ByteSize ? kMax8UnsignedImm : kMax16UnsignedImm;
10150         Operand &lastDestOpnd = GetCurBB()->GetLastMachineInsn()->GetOperand(kInsnFirstOpnd);
10151         DEBUG_ASSERT(lastDestOpnd.IsRegister(), "last insn's 1st operand is not register.");
10152         ImmOperand &immOpnd = CreateImmOperand(primType, maxIntVal);
10153         Insn &andInsn = GetInsnBuilder()->BuildInsn(MOP_wandrri12, lastDestOpnd, lastDestOpnd, immOpnd);
10154         GetCurBB()->AppendInsn(andInsn);
10155     }
10156 
10157     Operand *newVal = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnThirdOpnd));
10158     if (GetCG()->GetOptimizeLevel() != CGOptions::kLevel0) {
10159         SetCurBB(*atomicBB);
10160     }
10161 
10162     uint32 nodePrimTypeP2Size = GetPrimTypeP2Size(nodePrimType);
10163     /* ldxr */
10164     auto *regLoaded = &CreateRegisterOperandOfType(primType);
10165     auto &memOpnd = CreateMemOpnd(LoadIntoRegister(*addrOpnd, primType), 0, GetPrimTypeBitSize(primType));
10166     auto mOpLoad = PickLoadStoreExclInsn(nodePrimTypeP2Size, false, false);
10167     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpLoad, *regLoaded, memOpnd));
10168     Operand *regExtend = &CreateRegisterOperandOfType(primType);
10169     PrimType targetType = (oldVal->GetSize() <= k32BitSize) ? (IsSignedInteger(primType) ? PTY_i32 : PTY_u32)
10170                                                             : (IsSignedInteger(primType) ? PTY_i64 : PTY_u64);
10171     SelectCvtInt2Int(nullptr, regExtend, regLoaded, primType, targetType);
10172     /* cmp */
10173     SelectAArch64Cmp(*regExtend, *oldVal, true, oldVal->GetSize());
10174     /* bne */
10175     Operand &rflag = GetOrCreateRflag();
10176     LabelIdx nextBBLableIdx = CreateLabel();
10177     LabelOperand &targetOpnd = GetOrCreateLabelOperand(nextBBLableIdx);
10178     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_bne, rflag, targetOpnd));
10179     /* stlxr */
10180     BB *stlxrBB = CreateNewBB();
10181     stlxrBB->SetKind(BB::kBBIf);
10182     atomicBB->AppendBB(*stlxrBB);
10183     SetCurBB(*stlxrBB);
10184     auto *accessStatus = &CreateRegisterOperandOfType(PTY_u32);
10185     auto &newRegVal = LoadIntoRegister(*newVal, primType);
10186     auto mOpStore = PickLoadStoreExclInsn(nodePrimTypeP2Size, true, true);
10187     stlxrBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpStore, *accessStatus, newRegVal, memOpnd));
10188     /* cbnz ==> check the exclusive accsess status */
10189     auto &atomicBBOpnd = GetOrCreateLabelOperand(*atomicBB);
10190     stlxrBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wcbnz, *accessStatus, atomicBBOpnd));
10191     /* Data Memory Barrier */
10192     BB *nextBB = CreateNewBB();
10193     nextBB->AddLabel(nextBBLableIdx);
10194     nextBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ish, AArch64CG::kMd[MOP_dmb_ish]));
10195     /* special handle for boolean return type */
10196     if (intrinopNode.GetPrimType() == PTY_u1) {
10197         nextBB->AppendInsn(
10198             GetInsnBuilder()->BuildInsn(MOP_wandrri12, *regLoaded, *regLoaded, CreateImmOperand(PTY_u32, 1)));
10199     }
10200     SetLab2BBMap(static_cast<int32>(nextBBLableIdx), *nextBB);
10201     stlxrBB->AppendBB(*nextBB);
10202     SetCurBB(*nextBB);
10203     /* bool version return true if the comparison is successful and newval is written */
10204     if (retBool) {
10205         auto *retOpnd = &CreateRegisterOperandOfType(PTY_u32);
10206         SelectAArch64CSet(*retOpnd, GetCondOperand(CC_EQ), false);
10207         return retOpnd;
10208     }
10209     /* type version return the contents of *addrOpnd before the operation */
10210     return regLoaded;
10211 }
10212 
SelectCSyncFetch(IntrinsicopNode & intrinopNode,Opcode op,bool fetchBefore)10213 Operand *AArch64CGFunc::SelectCSyncFetch(IntrinsicopNode &intrinopNode, Opcode op, bool fetchBefore)
10214 {
10215     return SelectAArch64CSyncFetch(intrinopNode, op, fetchBefore);
10216 }
10217 
SelectCSyncBoolCmpSwap(IntrinsicopNode & intrinopNode)10218 Operand *AArch64CGFunc::SelectCSyncBoolCmpSwap(IntrinsicopNode &intrinopNode)
10219 {
10220     return SelectCSyncCmpSwap(intrinopNode, true);
10221 }
10222 
SelectCSyncValCmpSwap(IntrinsicopNode & intrinopNode)10223 Operand *AArch64CGFunc::SelectCSyncValCmpSwap(IntrinsicopNode &intrinopNode)
10224 {
10225     return SelectCSyncCmpSwap(intrinopNode);
10226 }
10227 
SelectCSyncLockTestSet(IntrinsicopNode & intrinopNode,PrimType pty)10228 Operand *AArch64CGFunc::SelectCSyncLockTestSet(IntrinsicopNode &intrinopNode, PrimType pty)
10229 {
10230     auto primType = intrinopNode.GetPrimType();
10231     /*handle builtin args */
10232     Operand *addrOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnFirstOpnd));
10233     Operand *valueOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnSecondOpnd));
10234     addrOpnd = &LoadIntoRegister(*addrOpnd, intrinopNode.GetNopndAt(kInsnFirstOpnd)->GetPrimType());
10235     valueOpnd = &LoadIntoRegister(*valueOpnd, intrinopNode.GetNopndAt(kInsnSecondOpnd)->GetPrimType());
10236 
10237     /* Create BB which includes atomic built_in function */
10238     LabelIdx atomicBBLabIdx = CreateLabel();
10239     BB *atomicBB = CreateNewBB();
10240     atomicBB->SetKind(BB::kBBIf);
10241     atomicBB->SetAtomicBuiltIn();
10242     atomicBB->AddLabel(atomicBBLabIdx);
10243     SetLab2BBMap(static_cast<int32>(atomicBBLabIdx), *atomicBB);
10244     GetCurBB()->AppendBB(*atomicBB);
10245     SetCurBB(*atomicBB);
10246     /* load from pointed address */
10247     auto primTypeP2Size = GetPrimTypeP2Size(primType);
10248     auto *regLoaded = &CreateRegisterOperandOfType(primType);
10249     auto &memOpnd = CreateMemOpnd(*static_cast<RegOperand *>(addrOpnd), 0, GetPrimTypeBitSize(primType));
10250     auto mOpLoad = PickLoadStoreExclInsn(primTypeP2Size, false, false);
10251     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpLoad, *regLoaded, memOpnd));
10252     /* store to pointed address */
10253     auto *accessStatus = &CreateRegisterOperandOfType(PTY_u32);
10254     auto mOpStore = PickLoadStoreExclInsn(primTypeP2Size, true, false);
10255     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(mOpStore, *accessStatus, *valueOpnd, memOpnd));
10256     /* check the exclusive accsess status */
10257     auto &atomicBBOpnd = GetOrCreateLabelOperand(*atomicBB);
10258     atomicBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wcbnz, *accessStatus, atomicBBOpnd));
10259 
10260     /* Data Memory Barrier */
10261     BB *nextBB = CreateNewBB();
10262     atomicBB->AppendBB(*nextBB);
10263     SetCurBB(*nextBB);
10264     nextBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_dmb_ish, AArch64CG::kMd[MOP_dmb_ish]));
10265     return regLoaded;
10266 }
10267 
SelectCSyncLockRelease(const IntrinsiccallNode & intrinsiccall,PrimType primType)10268 void AArch64CGFunc::SelectCSyncLockRelease(const IntrinsiccallNode &intrinsiccall, PrimType primType)
10269 {
10270     auto *addrOpnd = HandleExpr(intrinsiccall, *intrinsiccall.GetNopndAt(kInsnFirstOpnd));
10271     auto primTypeBitSize = GetPrimTypeBitSize(primType);
10272     auto mOp = PickStInsn(primTypeBitSize, primType, AArch64isa::kMoRelease);
10273     auto &zero = GetZeroOpnd(primTypeBitSize);
10274     auto &memOpnd = CreateMemOpnd(LoadIntoRegister(*addrOpnd, primType), 0, primTypeBitSize);
10275     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, zero, memOpnd));
10276 }
10277 
SelectCSyncSynchronize(IntrinsicopNode & intrinopNode)10278 Operand *AArch64CGFunc::SelectCSyncSynchronize(IntrinsicopNode &intrinopNode)
10279 {
10280     (void)intrinopNode;
10281     CHECK_FATAL(false, "have not implement SelectCSyncSynchronize yet");
10282     return nullptr;
10283 }
10284 
PickMemOrder(std::memory_order memOrder,bool isLdr) const10285 AArch64isa::MemoryOrdering AArch64CGFunc::PickMemOrder(std::memory_order memOrder, bool isLdr) const
10286 {
10287     switch (memOrder) {
10288         case std::memory_order_relaxed:
10289             return AArch64isa::kMoNone;
10290         case std::memory_order_consume:
10291         case std::memory_order_acquire:
10292             return isLdr ? AArch64isa::kMoAcquire : AArch64isa::kMoNone;
10293         case std::memory_order_release:
10294             return isLdr ? AArch64isa::kMoNone : AArch64isa::kMoRelease;
10295         case std::memory_order_acq_rel:
10296         case std::memory_order_seq_cst:
10297             return isLdr ? AArch64isa::kMoAcquire : AArch64isa::kMoRelease;
10298         default:
10299             CHECK_FATAL(false, "unexpected memorder");
10300             return AArch64isa::kMoNone;
10301     }
10302 }
10303 
10304 /*
10305  * regassign %1 (intrinsicop C___Atomic_Load_N(ptr, memorder))
10306  * ====> %1 = *ptr
10307  * let %1 -> x0
10308  * let ptr -> x1
10309  * implement to asm: ldr/ldar x0, [x1]
10310  * a load-acquire would replace ldr if memorder is not 0
10311  */
SelectCAtomicLoadN(IntrinsicopNode & intrinsicopNode)10312 Operand *AArch64CGFunc::SelectCAtomicLoadN(IntrinsicopNode &intrinsicopNode)
10313 {
10314     auto *addrOpnd = HandleExpr(intrinsicopNode, *intrinsicopNode.Opnd(0));
10315     auto *memOrderOpnd = intrinsicopNode.Opnd(1);
10316     auto primType = intrinsicopNode.GetPrimType();
10317     std::memory_order memOrder = std::memory_order_seq_cst;
10318     if (memOrderOpnd->IsConstval()) {
10319         auto *memOrderConst = static_cast<MIRIntConst *>(static_cast<ConstvalNode *>(memOrderOpnd)->GetConstVal());
10320         memOrder = static_cast<std::memory_order>(memOrderConst->GetExtValue());
10321     }
10322     return SelectAtomicLoad(*addrOpnd, primType, PickMemOrder(memOrder, true));
10323 }
10324 
10325 /*
10326  * regassign %1 (intrinsicop C___Atomic_exchange_n(ptr, val, memorder))
10327  * ====> %1 = *ptr; *ptr = val;
10328  * let %1 -> x0
10329  * let ptr -> x1
10330  * let val -> x2
10331  * implement to asm:
10332  * ldr/ldar x0, [x1]
10333  * str/stlr x2, [x1]
10334  * a load-acquire would replace ldr if acquire needed
10335  * a store-relase would replace str if release needed
10336  */
SelectCAtomicExchangeN(const IntrinsiccallNode & intrinsiccallNode)10337 Operand *AArch64CGFunc::SelectCAtomicExchangeN(const IntrinsiccallNode &intrinsiccallNode)
10338 {
10339     auto primType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(intrinsiccallNode.GetTyIdx())->GetPrimType();
10340     auto *addrOpnd = HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(0));
10341     auto *valueOpnd = HandleExpr(intrinsiccallNode, *intrinsiccallNode.Opnd(1));
10342     auto *memOrderOpnd = intrinsiccallNode.Opnd(kInsnThirdOpnd);
10343 
10344     /* slect memry order */
10345     std::memory_order memOrder = std::memory_order_seq_cst;
10346     if (memOrderOpnd->IsConstval()) {
10347         auto *memOrderConst = static_cast<MIRIntConst *>(static_cast<ConstvalNode *>(memOrderOpnd)->GetConstVal());
10348         memOrder = static_cast<std::memory_order>(memOrderConst->GetExtValue());
10349     }
10350     auto *result = SelectAtomicLoad(*addrOpnd, primType, PickMemOrder(memOrder, true));
10351     SelectAtomicStore(*valueOpnd, *addrOpnd, primType, PickMemOrder(memOrder, false));
10352     return result;
10353 }
10354 
SelectAtomicLoad(Operand & addrOpnd,PrimType primType,AArch64isa::MemoryOrdering memOrder)10355 Operand *AArch64CGFunc::SelectAtomicLoad(Operand &addrOpnd, PrimType primType, AArch64isa::MemoryOrdering memOrder)
10356 {
10357     auto mOp = PickLdInsn(GetPrimTypeBitSize(primType), primType, memOrder);
10358     auto &memOpnd = CreateMemOpnd(LoadIntoRegister(addrOpnd, PTY_a64), 0, k64BitSize);
10359     auto *resultOpnd = &CreateRegisterOperandOfType(primType);
10360     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, *resultOpnd, memOpnd));
10361     return resultOpnd;
10362 }
10363 
SelectCReturnAddress(IntrinsicopNode & intrinopNode)10364 Operand *AArch64CGFunc::SelectCReturnAddress(IntrinsicopNode &intrinopNode)
10365 {
10366     if (intrinopNode.GetIntrinsic() == INTRN_C__builtin_extract_return_addr) {
10367         DEBUG_ASSERT(intrinopNode.GetNumOpnds() == 1, "expect one parameter");
10368         Operand *addrOpnd = HandleExpr(intrinopNode, *intrinopNode.GetNopndAt(kInsnFirstOpnd));
10369         return &LoadIntoRegister(*addrOpnd, PTY_a64);
10370     } else if (intrinopNode.GetIntrinsic() == INTRN_C__builtin_return_address) {
10371         BaseNode *argexpr0 = intrinopNode.Opnd(0);
10372         while (!argexpr0->IsLeaf()) {
10373             argexpr0 = argexpr0->Opnd(0);
10374         }
10375         CHECK_FATAL(argexpr0->IsConstval(), "Invalid argument of __builtin_return_address");
10376         auto &constNode = static_cast<ConstvalNode &>(*argexpr0);
10377         DEBUG_ASSERT(constNode.GetConstVal()->GetKind() == kConstInt, "expect MIRIntConst does not support float yet");
10378         MIRIntConst *mirIntConst = safe_cast<MIRIntConst>(constNode.GetConstVal());
10379         DEBUG_ASSERT(mirIntConst != nullptr, "nullptr checking");
10380         int64 scale = mirIntConst->GetExtValue();
10381         /*
10382          * Do not support getting return address with a nonzero argument
10383          * inline / tail call opt will destory this behavior
10384          */
10385         CHECK_FATAL(scale == 0, "Do not support recursion");
10386         Operand *resReg = &static_cast<Operand &>(CreateRegisterOperandOfType(PTY_i64));
10387         SelectCopy(*resReg, PTY_i64, GetOrCreatePhysicalRegisterOperand(RLR, k64BitSize, kRegTyInt), PTY_i64);
10388         return resReg;
10389     }
10390     return nullptr;
10391 }
10392 
SelectCalignup(IntrinsicopNode & intrnNode)10393 Operand *AArch64CGFunc::SelectCalignup(IntrinsicopNode &intrnNode)
10394 {
10395     return SelectAArch64align(intrnNode, true);
10396 }
10397 
SelectCaligndown(IntrinsicopNode & intrnNode)10398 Operand *AArch64CGFunc::SelectCaligndown(IntrinsicopNode &intrnNode)
10399 {
10400     return SelectAArch64align(intrnNode, false);
10401 }
10402 
SelectAArch64align(const IntrinsicopNode & intrnNode,bool isUp)10403 Operand *AArch64CGFunc::SelectAArch64align(const IntrinsicopNode &intrnNode, bool isUp)
10404 {
10405     /* Handle Two args */
10406     BaseNode *argexpr0 = intrnNode.Opnd(0);
10407     PrimType ptype0 = argexpr0->GetPrimType();
10408     Operand *opnd0 = HandleExpr(intrnNode, *argexpr0);
10409     PrimType resultPtype = intrnNode.GetPrimType();
10410     RegOperand &ldDest0 = LoadIntoRegister(*opnd0, ptype0);
10411 
10412     BaseNode *argexpr1 = intrnNode.Opnd(1);
10413     PrimType ptype1 = argexpr1->GetPrimType();
10414     Operand *opnd1 = HandleExpr(intrnNode, *argexpr1);
10415     RegOperand &arg1 = LoadIntoRegister(*opnd1, ptype1);
10416     DEBUG_ASSERT(IsPrimitiveInteger(ptype0) && IsPrimitiveInteger(ptype1), "align integer type only");
10417     Operand *ldDest1 = &static_cast<Operand &>(CreateRegisterOperandOfType(ptype0));
10418     SelectCvtInt2Int(nullptr, ldDest1, &arg1, ptype1, ptype0);
10419 
10420     Operand *resultReg = &static_cast<Operand &>(CreateRegisterOperandOfType(ptype0));
10421     Operand &immReg = CreateImmOperand(1, GetPrimTypeBitSize(ptype0), true);
10422     /* Do alignment  x0 -- value to be aligned   x1 -- alignment */
10423     if (isUp) {
10424         /* add res, x0, x1 */
10425         SelectAdd(*resultReg, ldDest0, *ldDest1, ptype0);
10426         /* sub res, res, 1 */
10427         SelectSub(*resultReg, *resultReg, immReg, ptype0);
10428     }
10429     Operand *tempReg = &static_cast<Operand &>(CreateRegisterOperandOfType(ptype0));
10430     /* sub temp, x1, 1 */
10431     SelectSub(*tempReg, *ldDest1, immReg, ptype0);
10432     /* mvn temp, temp */
10433     SelectMvn(*tempReg, *tempReg, ptype0);
10434     /* and res, res, temp */
10435     if (isUp) {
10436         SelectBand(*resultReg, *resultReg, *tempReg, ptype0);
10437     } else {
10438         SelectBand(*resultReg, ldDest0, *tempReg, ptype0);
10439     }
10440     if (resultPtype != ptype0) {
10441         SelectCvtInt2Int(&intrnNode, resultReg, resultReg, ptype0, resultPtype);
10442     }
10443     return resultReg;
10444 }
10445 
SelectCDIVException()10446 void AArch64CGFunc::SelectCDIVException()
10447 {
10448     uint32 breakImm = 1000;
10449     ImmOperand &immOpnd = CreateImmOperand(breakImm, maplebe::k16BitSize, false);
10450     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_brk, immOpnd));
10451 }
10452 
10453 /*
10454  * NOTE: consider moving the following things into aarch64_cg.cpp  They may
10455  * serve not only inrinsics, but other MapleIR instructions as well.
10456  * Do it as if we are adding a label in straight-line assembly code.
10457  */
CreateLabeledBB(StmtNode & stmt)10458 LabelIdx AArch64CGFunc::CreateLabeledBB(StmtNode &stmt)
10459 {
10460     LabelIdx labIdx = CreateLabel();
10461     BB *newBB = StartNewBBImpl(false, stmt);
10462     newBB->AddLabel(labIdx);
10463     SetLab2BBMap(labIdx, *newBB);
10464     SetCurBB(*newBB);
10465     return labIdx;
10466 }
10467 
10468 /* Save value into the local variable for the index-th return value; */
SaveReturnValueInLocal(CallReturnVector & retVals,size_t index,PrimType primType,Operand & value,StmtNode & parentStmt)10469 void AArch64CGFunc::SaveReturnValueInLocal(CallReturnVector &retVals, size_t index, PrimType primType, Operand &value,
10470                                            StmtNode &parentStmt)
10471 {
10472     CallReturnPair &pair = retVals.at(index);
10473     BB tempBB(static_cast<uint32>(-1), *GetFuncScopeAllocator());
10474     BB *realCurBB = GetCurBB();
10475     CHECK_FATAL(!pair.second.IsReg(), "NYI");
10476     Operand *destOpnd = &value;
10477     /* for O0 ,corss-BB var is not support, do extra store/load but why new BB */
10478     if (GetCG()->GetOptimizeLevel() == CGOptions::kLevel0) {
10479         MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(pair.first);
10480         DEBUG_ASSERT(symbol != nullptr, "symbol should not be nullptr");
10481         MIRType *sPty = symbol->GetType();
10482         PrimType ty = symbol->GetType()->GetPrimType();
10483         if (sPty->GetKind() == kTypeStruct || sPty->GetKind() == kTypeUnion) {
10484             MIRStructType *structType = static_cast<MIRStructType *>(sPty);
10485             ty = structType->GetFieldType(pair.second.GetFieldID())->GetPrimType();
10486         } else if (sPty->GetKind() == kTypeClass) {
10487             CHECK_FATAL(false, "unsuppotr type for inlineasm / intrinsic");
10488         }
10489         RegOperand &tempReg = CreateVirtualRegisterOperand(NewVReg(GetRegTyFromPrimTy(ty), GetPrimTypeSize(ty)));
10490         SelectCopy(tempReg, ty, value, ty);
10491         destOpnd = &tempReg;
10492     }
10493     SetCurBB(tempBB);
10494     SelectDassign(pair.first, pair.second.GetFieldID(), primType, *destOpnd);
10495 
10496     CHECK_FATAL(realCurBB->GetNext() == nullptr, "current BB must has not nextBB");
10497     realCurBB->SetLastStmt(parentStmt);
10498     realCurBB->SetNext(StartNewBBImpl(true, parentStmt));
10499     realCurBB->GetNext()->SetKind(BB::kBBFallthru);
10500     realCurBB->GetNext()->SetPrev(realCurBB);
10501 
10502     realCurBB->GetNext()->InsertAtBeginning(*GetCurBB());
10503     /* restore it */
10504     SetCurBB(*realCurBB->GetNext());
10505 }
10506 
10507 /* The following are translation of LL/SC and atomic RMW operations */
OperandToMemOrd(Operand & opnd) const10508 MemOrd AArch64CGFunc::OperandToMemOrd(Operand &opnd) const
10509 {
10510     CHECK_FATAL(opnd.IsImmediate(), "Memory order must be an int constant.");
10511     auto immOpnd = static_cast<ImmOperand *>(&opnd);
10512     int32 val = immOpnd->GetValue();
10513     CHECK_FATAL(val >= 0, "val must be non-negtive");
10514     return MemOrdFromU32(static_cast<uint32>(val));
10515 }
10516 
10517 /*
10518  * Generate ldxr or ldaxr instruction.
10519  * byte_p2x: power-of-2 size of operand in bytes (0: 1B, 1: 2B, 2: 4B, 3: 8B).
10520  */
PickLoadStoreExclInsn(uint32 byteP2Size,bool store,bool acqRel) const10521 MOperator AArch64CGFunc::PickLoadStoreExclInsn(uint32 byteP2Size, bool store, bool acqRel) const
10522 {
10523     CHECK_FATAL(byteP2Size < kIntByteSizeDimension, "Illegal argument p2size: %d", byteP2Size);
10524 
10525     static MOperator operators[4][2][2] = {{{MOP_wldxrb, MOP_wldaxrb}, {MOP_wstxrb, MOP_wstlxrb}},
10526                                            {{MOP_wldxrh, MOP_wldaxrh}, {MOP_wstxrh, MOP_wstlxrh}},
10527                                            {{MOP_wldxr, MOP_wldaxr}, {MOP_wstxr, MOP_wstlxr}},
10528                                            {{MOP_xldxr, MOP_xldaxr}, {MOP_xstxr, MOP_xstlxr}}};
10529 
10530     MOperator optr = operators[byteP2Size][store][acqRel];
10531     CHECK_FATAL(optr != MOP_undef, "Unsupported type p2size: %d", byteP2Size);
10532 
10533     return optr;
10534 }
10535 
SelectLoadExcl(PrimType valPrimType,MemOperand & loc,bool acquire)10536 RegOperand *AArch64CGFunc::SelectLoadExcl(PrimType valPrimType, MemOperand &loc, bool acquire)
10537 {
10538     uint32 p2size = GetPrimTypeP2Size(valPrimType);
10539 
10540     RegOperand &result = CreateRegisterOperandOfType(valPrimType);
10541     MOperator mOp = PickLoadStoreExclInsn(p2size, false, acquire);
10542     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, result, loc));
10543 
10544     return &result;
10545 }
10546 
SelectStoreExcl(PrimType valPty,MemOperand & loc,RegOperand & newVal,bool release)10547 RegOperand *AArch64CGFunc::SelectStoreExcl(PrimType valPty, MemOperand &loc, RegOperand &newVal, bool release)
10548 {
10549     uint32 p2size = GetPrimTypeP2Size(valPty);
10550 
10551     /* the result (success/fail) is to be stored in a 32-bit register */
10552     RegOperand &result = CreateRegisterOperandOfType(PTY_u32);
10553 
10554     MOperator mOp = PickLoadStoreExclInsn(p2size, true, release);
10555     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, result, newVal, loc));
10556 
10557     return &result;
10558 }
10559 
GetRegisterType(regno_t reg) const10560 RegType AArch64CGFunc::GetRegisterType(regno_t reg) const
10561 {
10562     if (AArch64isa::IsPhysicalRegister(reg)) {
10563         return AArch64isa::GetRegType(static_cast<AArch64reg>(reg));
10564     } else if (reg == kRFLAG) {
10565         return kRegTyCc;
10566     } else {
10567         return CGFunc::GetRegisterType(reg);
10568     }
10569 }
10570 
LoadStructCopyBase(const MIRSymbol & symbol,int64 offset,int dataSize)10571 MemOperand &AArch64CGFunc::LoadStructCopyBase(const MIRSymbol &symbol, int64 offset, int dataSize)
10572 {
10573     /* For struct formals > 16 bytes, this is the pointer to the struct copy. */
10574     /* Load the base pointer first. */
10575     RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize));
10576     MemOperand *baseMemOpnd = &GetOrCreateMemOpnd(symbol, 0, k64BitSize);
10577     GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *baseMemOpnd));
10578     /* Create the indirect load mem opnd from the base pointer. */
10579     return CreateMemOpnd(*vreg, offset, static_cast<uint32>(dataSize));
10580 }
10581 
10582 /* For long branch, insert an unconditional branch.
10583  * From                      To
10584  *   cond_br targe_label       reverse_cond_br fallthru_label
10585  *   fallthruBB                unconditional br target_label
10586  *                             fallthru_label:
10587  *                             fallthruBB
10588  */
InsertJumpPad(Insn * insn)10589 void AArch64CGFunc::InsertJumpPad(Insn *insn)
10590 {
10591     BB *bb = insn->GetBB();
10592     DEBUG_ASSERT(bb, "instruction has no bb");
10593     DEBUG_ASSERT(bb->GetKind() == BB::kBBIf || bb->GetKind() == BB::kBBGoto,
10594                  "instruction is in neither if bb nor goto bb");
10595     if (bb->GetKind() == BB::kBBGoto) {
10596         return;
10597     }
10598     DEBUG_ASSERT(bb->NumSuccs() == k2ByteSize, "if bb should have 2 successors");
10599 
10600     BB *longBrBB = CreateNewBB();
10601 
10602     BB *fallthruBB = bb->GetNext();
10603     LabelIdx fallthruLBL = fallthruBB->GetLabIdx();
10604     if (fallthruLBL == 0) {
10605         fallthruLBL = CreateLabel();
10606         SetLab2BBMap(static_cast<int32>(fallthruLBL), *fallthruBB);
10607         fallthruBB->AddLabel(fallthruLBL);
10608     }
10609 
10610     BB *targetBB;
10611     if (bb->GetSuccs().front() == fallthruBB) {
10612         targetBB = bb->GetSuccs().back();
10613     } else {
10614         targetBB = bb->GetSuccs().front();
10615     }
10616     LabelIdx targetLBL = targetBB->GetLabIdx();
10617     if (targetLBL == 0) {
10618         targetLBL = CreateLabel();
10619         SetLab2BBMap(static_cast<int32>(targetLBL), *targetBB);
10620         targetBB->AddLabel(targetLBL);
10621     }
10622 
10623     // Adjustment on br and CFG
10624     bb->RemoveSuccs(*targetBB);
10625     bb->PushBackSuccs(*longBrBB);
10626     bb->SetNext(longBrBB);
10627     // reverse cond br targeting fallthruBB
10628     uint32 targetIdx = AArch64isa::GetJumpTargetIdx(*insn);
10629     MOperator mOp = AArch64isa::FlipConditionOp(insn->GetMachineOpcode());
10630     insn->SetMOP(AArch64CG::kMd[mOp]);
10631     LabelOperand &fallthruBBLBLOpnd = GetOrCreateLabelOperand(fallthruLBL);
10632     insn->SetOperand(targetIdx, fallthruBBLBLOpnd);
10633 
10634     longBrBB->PushBackPreds(*bb);
10635     longBrBB->PushBackSuccs(*targetBB);
10636     LabelOperand &targetLBLOpnd = GetOrCreateLabelOperand(targetLBL);
10637     longBrBB->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xuncond, targetLBLOpnd));
10638     longBrBB->SetPrev(bb);
10639     longBrBB->SetNext(fallthruBB);
10640     longBrBB->SetKind(BB::kBBGoto);
10641 
10642     fallthruBB->SetPrev(longBrBB);
10643 
10644     targetBB->RemovePreds(*bb);
10645     targetBB->PushBackPreds(*longBrBB);
10646 }
10647 
AdjustOneElementVectorOperand(PrimType oType,RegOperand * opnd)10648 RegOperand *AArch64CGFunc::AdjustOneElementVectorOperand(PrimType oType, RegOperand *opnd)
10649 {
10650     RegOperand *resCvt = &CreateRegisterOperandOfType(oType);
10651     Insn *insnCvt = &GetInsnBuilder()->BuildInsn(MOP_xvmovrd, *resCvt, *opnd);
10652     GetCurBB()->AppendInsn(*insnCvt);
10653     return resCvt;
10654 }
10655 
SelectOneElementVectorCopy(Operand * src,PrimType sType)10656 RegOperand *AArch64CGFunc::SelectOneElementVectorCopy(Operand *src, PrimType sType)
10657 {
10658     RegOperand *res = &CreateRegisterOperandOfType(PTY_f64);
10659     SelectCopy(*res, PTY_f64, *src, sType);
10660     static_cast<RegOperand *>(res)->SetIF64Vec();
10661     return res;
10662 }
10663 
SelectVectorAbs(PrimType rType,Operand * o1)10664 RegOperand *AArch64CGFunc::SelectVectorAbs(PrimType rType, Operand *o1)
10665 {
10666     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
10667     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10668     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
10669 
10670     MOperator mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vabsvv : MOP_vabsuu;
10671     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10672     vInsn.AddOpndChain(*res).AddOpndChain(*o1);
10673     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
10674     GetCurBB()->AppendInsn(vInsn);
10675     return res;
10676 }
10677 
SelectVectorAddLong(PrimType rType,Operand * o1,Operand * o2,PrimType otyp,bool isLow)10678 RegOperand *AArch64CGFunc::SelectVectorAddLong(PrimType rType, Operand *o1, Operand *o2, PrimType otyp, bool isLow)
10679 {
10680     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result type */
10681     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10682     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(otyp); /* vector operand 1 */
10683     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(otyp); /* vector operand 2 */
10684     MOperator mOp;
10685     if (isLow) {
10686         mOp = IsUnsignedInteger(rType) ? MOP_vuaddlvuu : MOP_vsaddlvuu;
10687     } else {
10688         mOp = IsUnsignedInteger(rType) ? MOP_vuaddl2vvv : MOP_vsaddl2vvv;
10689     }
10690     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10691     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
10692     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
10693     GetCurBB()->AppendInsn(vInsn);
10694     return res;
10695 }
10696 
SelectVectorAddWiden(Operand * o1,PrimType otyp1,Operand * o2,PrimType otyp2,bool isLow)10697 RegOperand *AArch64CGFunc::SelectVectorAddWiden(Operand *o1, PrimType otyp1, Operand *o2, PrimType otyp2, bool isLow)
10698 {
10699     RegOperand *res = &CreateRegisterOperandOfType(otyp1); /* restype is same as o1 */
10700     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(otyp1);
10701     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(otyp1); /* vector operand 1 */
10702     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(otyp2); /* vector operand 2 */
10703 
10704     MOperator mOp;
10705     if (isLow) {
10706         mOp = IsUnsignedInteger(otyp1) ? MOP_vuaddwvvu : MOP_vsaddwvvu;
10707     } else {
10708         mOp = IsUnsignedInteger(otyp1) ? MOP_vuaddw2vvv : MOP_vsaddw2vvv;
10709     }
10710     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10711     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
10712     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
10713     GetCurBB()->AppendInsn(vInsn);
10714     return res;
10715 }
10716 
SelectVectorImmMov(PrimType rType,Operand * src,PrimType sType)10717 RegOperand *AArch64CGFunc::SelectVectorImmMov(PrimType rType, Operand *src, PrimType sType)
10718 {
10719     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
10720     VectorRegSpec *vecSpec = GetMemoryPool()->New<VectorRegSpec>(rType);
10721     int64 val = static_cast<ImmOperand *>(src)->GetValue();
10722     /* copy the src imm operand to a reg if out of range */
10723     if ((GetVecEleSize(rType) >= k64BitSize) || (GetPrimTypeSize(sType) > k4ByteSize && val != 0) ||
10724         (val < kMinImmVal || val > kMaxImmVal)) {
10725         Operand *reg = &CreateRegisterOperandOfType(sType);
10726         SelectCopy(*reg, sType, *src, sType);
10727         return SelectVectorRegMov(rType, reg, sType);
10728     }
10729 
10730     MOperator mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vmovvi : MOP_vmovui;
10731     if (GetVecEleSize(rType) == k8BitSize && val < 0) {
10732         src = &CreateImmOperand(static_cast<uint8>(val), k8BitSize, true);
10733     } else if (val < 0) {
10734         src = &CreateImmOperand(-(val + 1), k8BitSize, true);
10735         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vnotvi : MOP_vnotui;
10736     }
10737 
10738     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10739     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10740     vInsn.PushRegSpecEntry(vecSpec);
10741     GetCurBB()->AppendInsn(vInsn);
10742     return res;
10743 }
10744 
SelectVectorRegMov(PrimType rType,Operand * src,PrimType sType)10745 RegOperand *AArch64CGFunc::SelectVectorRegMov(PrimType rType, Operand *src, PrimType sType)
10746 {
10747     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
10748     VectorRegSpec *vecSpec = GetMemoryPool()->New<VectorRegSpec>(rType);
10749 
10750     MOperator mOp;
10751     if (GetPrimTypeSize(sType) > k4ByteSize) {
10752         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vxdupvr : MOP_vxdupur;
10753     } else {
10754         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vwdupvr : MOP_vwdupur;
10755     }
10756 
10757     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10758     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10759     vInsn.PushRegSpecEntry(vecSpec);
10760     GetCurBB()->AppendInsn(vInsn);
10761     return res;
10762 }
10763 
SelectVectorFromScalar(PrimType rType,Operand * src,PrimType sType)10764 RegOperand *AArch64CGFunc::SelectVectorFromScalar(PrimType rType, Operand *src, PrimType sType)
10765 {
10766     if (!IsPrimitiveVector(rType)) {
10767         return SelectOneElementVectorCopy(src, sType);
10768     } else if (src->IsConstImmediate()) {
10769         return SelectVectorImmMov(rType, src, sType);
10770     } else {
10771         return SelectVectorRegMov(rType, src, sType);
10772     }
10773 }
10774 
SelectVectorDup(PrimType rType,Operand * src,bool getLow)10775 RegOperand *AArch64CGFunc::SelectVectorDup(PrimType rType, Operand *src, bool getLow)
10776 {
10777     PrimType oType = rType;
10778     rType = FilterOneElementVectorType(oType);
10779     RegOperand *res = &CreateRegisterOperandOfType(rType);
10780     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(k2ByteSize, k64BitSize, getLow ? 0 : 1);
10781 
10782     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(MOP_vduprv, AArch64CG::kMd[MOP_vduprv]);
10783     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10784     vInsn.PushRegSpecEntry(vecSpecSrc);
10785     GetCurBB()->AppendInsn(vInsn);
10786     if (oType != rType) {
10787         res = AdjustOneElementVectorOperand(oType, res);
10788         static_cast<RegOperand *>(res)->SetIF64Vec();
10789     }
10790     return res;
10791 }
10792 
SelectVectorGetElement(PrimType rType,Operand * src,PrimType sType,int32 lane)10793 RegOperand *AArch64CGFunc::SelectVectorGetElement(PrimType rType, Operand *src, PrimType sType, int32 lane)
10794 {
10795     RegOperand *res = &CreateRegisterOperandOfType(rType);                        /* result operand */
10796     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(sType, lane); /* vector operand */
10797 
10798     MOperator mop;
10799     if (!IsPrimitiveVector(sType)) {
10800         mop = MOP_xmovrr;
10801     } else if (GetPrimTypeBitSize(rType) >= k64BitSize) {
10802         mop = MOP_vxmovrv;
10803     } else {
10804         mop = (GetPrimTypeBitSize(sType) > k64BitSize) ? MOP_vwmovrv : MOP_vwmovru;
10805     }
10806 
10807     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
10808     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10809     vInsn.PushRegSpecEntry(vecSpecSrc);
10810     GetCurBB()->AppendInsn(vInsn);
10811     return res;
10812 }
10813 
10814 /* adalp o1, o2 instruction accumulates into o1, overwriting the original operand.
10815    Hence we perform c = vadalp(a,b) as
10816        T tmp = a;
10817        return tmp+b;
10818    The return value of vadalp is then assigned to c, leaving value of a intact.
10819  */
SelectVectorPairwiseAdalp(Operand * src1,PrimType sty1,Operand * src2,PrimType sty2)10820 RegOperand *AArch64CGFunc::SelectVectorPairwiseAdalp(Operand *src1, PrimType sty1, Operand *src2, PrimType sty2)
10821 {
10822     VectorRegSpec *vecSpecDest;
10823     RegOperand *res;
10824 
10825     if (!IsPrimitiveVector(sty1)) {
10826         RegOperand *resF = SelectOneElementVectorCopy(src1, sty1);
10827         res = &CreateRegisterOperandOfType(PTY_f64);
10828         SelectCopy(*res, PTY_f64, *resF, PTY_f64);
10829         vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(k1ByteSize, k64BitSize);
10830     } else {
10831         res = &CreateRegisterOperandOfType(sty1); /* result type same as sty1 */
10832         SelectCopy(*res, sty1, *src1, sty1);
10833         vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(sty1);
10834     }
10835     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(sty2);
10836 
10837     MOperator mop;
10838     if (IsUnsignedInteger(sty1)) {
10839         mop = GetPrimTypeSize(sty1) > k8ByteSize ? MOP_vupadalvv : MOP_vupadaluu;
10840     } else {
10841         mop = GetPrimTypeSize(sty1) > k8ByteSize ? MOP_vspadalvv : MOP_vspadaluu;
10842     }
10843 
10844     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
10845     vInsn.AddOpndChain(*res).AddOpndChain(*src2);
10846     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecSrc);
10847     GetCurBB()->AppendInsn(vInsn);
10848     if (!IsPrimitiveVector(sty1)) {
10849         res = AdjustOneElementVectorOperand(sty1, res);
10850     }
10851     return res;
10852 }
10853 
SelectVectorPairwiseAdd(PrimType rType,Operand * src,PrimType sType)10854 RegOperand *AArch64CGFunc::SelectVectorPairwiseAdd(PrimType rType, Operand *src, PrimType sType)
10855 {
10856     PrimType oType = rType;
10857     rType = FilterOneElementVectorType(oType);
10858     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
10859     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10860     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(sType); /* source operand */
10861 
10862     if (rType == PTY_f64) {
10863         vecSpecDest->vecLaneMax = 1;
10864     }
10865 
10866     MOperator mop;
10867     if (IsUnsignedInteger(sType)) {
10868         mop = GetPrimTypeSize(sType) > k8ByteSize ? MOP_vupaddvv : MOP_vupadduu;
10869     } else {
10870         mop = GetPrimTypeSize(sType) > k8ByteSize ? MOP_vspaddvv : MOP_vspadduu;
10871     }
10872 
10873     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
10874     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10875     /* dest pushed first, popped first */
10876     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecSrc);
10877     GetCurBB()->AppendInsn(vInsn);
10878     if (oType != rType) {
10879         res = AdjustOneElementVectorOperand(oType, res);
10880     }
10881     return res;
10882 }
10883 
SelectVectorSetElement(Operand * eOpnd,PrimType eType,Operand * vOpnd,PrimType vType,int32 lane)10884 RegOperand *AArch64CGFunc::SelectVectorSetElement(Operand *eOpnd, PrimType eType, Operand *vOpnd, PrimType vType,
10885                                                   int32 lane)
10886 {
10887     if (!IsPrimitiveVector(vType)) {
10888         return SelectOneElementVectorCopy(eOpnd, eType);
10889     }
10890     RegOperand *reg = &CreateRegisterOperandOfType(eType); /* vector element type */
10891     SelectCopy(*reg, eType, *eOpnd, eType);
10892     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(vType, lane); /* vector operand == result */
10893 
10894     MOperator mOp;
10895     if (GetPrimTypeSize(eType) > k4ByteSize) {
10896         mOp = GetPrimTypeSize(vType) > k8ByteSize ? MOP_vxinsvr : MOP_vxinsur;
10897     } else {
10898         mOp = GetPrimTypeSize(vType) > k8ByteSize ? MOP_vwinsvr : MOP_vwinsur;
10899     }
10900 
10901     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10902     vInsn.AddOpndChain(*vOpnd).AddOpndChain(*reg);
10903     vInsn.PushRegSpecEntry(vecSpecSrc);
10904     GetCurBB()->AppendInsn(vInsn);
10905     return static_cast<RegOperand *>(vOpnd);
10906 }
10907 
SelectVectorAbsSubL(PrimType rType,Operand * o1,Operand * o2,PrimType oTy,bool isLow)10908 RegOperand *AArch64CGFunc::SelectVectorAbsSubL(PrimType rType, Operand *o1, Operand *o2, PrimType oTy, bool isLow)
10909 {
10910     RegOperand *res = &CreateRegisterOperandOfType(rType);
10911     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10912     VectorRegSpec *vecSpecOpd1 = GetMemoryPool()->New<VectorRegSpec>(oTy);
10913     VectorRegSpec *vecSpecOpd2 = GetMemoryPool()->New<VectorRegSpec>(oTy); /* same opnd types */
10914 
10915     MOperator mop;
10916     if (isLow) {
10917         mop = IsPrimitiveUnSignedVector(rType) ? MOP_vuabdlvuu : MOP_vsabdlvuu;
10918     } else {
10919         mop = IsPrimitiveUnSignedVector(rType) ? MOP_vuabdl2vvv : MOP_vsabdl2vvv;
10920     }
10921     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
10922     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
10923     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecOpd1).PushRegSpecEntry(vecSpecOpd2);
10924     GetCurBB()->AppendInsn(vInsn);
10925     return res;
10926 }
10927 
SelectVectorMerge(PrimType rType,Operand * o1,Operand * o2,int32 index)10928 RegOperand *AArch64CGFunc::SelectVectorMerge(PrimType rType, Operand *o1, Operand *o2, int32 index)
10929 {
10930     if (!IsPrimitiveVector(rType)) {
10931         static_cast<RegOperand *>(o1)->SetIF64Vec();
10932         return static_cast<RegOperand *>(o1); /* 64x1_t, index equals 0 */
10933     }
10934     RegOperand *res = &CreateRegisterOperandOfType(rType);
10935     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10936     VectorRegSpec *vecSpecOpd1 = GetMemoryPool()->New<VectorRegSpec>(rType);
10937     VectorRegSpec *vecSpecOpd2 = GetMemoryPool()->New<VectorRegSpec>(rType);
10938 
10939     ImmOperand *imm = &CreateImmOperand(index, k8BitSize, true);
10940 
10941     MOperator mOp = (GetPrimTypeSize(rType) > k8ByteSize) ? MOP_vextvvvi : MOP_vextuuui;
10942     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10943     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2).AddOpndChain(*imm);
10944     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecOpd1).PushRegSpecEntry(vecSpecOpd2);
10945     GetCurBB()->AppendInsn(vInsn);
10946     return res;
10947 }
10948 
SelectVectorReverse(PrimType rType,Operand * src,PrimType sType,uint32 size)10949 RegOperand *AArch64CGFunc::SelectVectorReverse(PrimType rType, Operand *src, PrimType sType, uint32 size)
10950 {
10951     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
10952     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
10953     VectorRegSpec *vecSpecSrc = GetMemoryPool()->New<VectorRegSpec>(sType); /* vector operand */
10954 
10955     MOperator mOp;
10956     if (GetPrimTypeBitSize(rType) == k128BitSize) {
10957         mOp = size >= k64BitSize ? MOP_vrev64qq : (size >= k32BitSize ? MOP_vrev32qq : MOP_vrev16qq);
10958     } else if (GetPrimTypeBitSize(rType) == k64BitSize) {
10959         mOp = size >= k64BitSize ? MOP_vrev64dd : (size >= k32BitSize ? MOP_vrev32dd : MOP_vrev16dd);
10960     } else {
10961         CHECK_FATAL(false, "should not be here");
10962     }
10963     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10964     vInsn.AddOpndChain(*res).AddOpndChain(*src);
10965     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpecSrc);
10966     GetCurBB()->AppendInsn(vInsn);
10967     return res;
10968 }
10969 
SelectVectorSum(PrimType rType,Operand * o1,PrimType oType)10970 RegOperand *AArch64CGFunc::SelectVectorSum(PrimType rType, Operand *o1, PrimType oType)
10971 {
10972     RegOperand *res = &CreateRegisterOperandOfType(rType); /* uint32_t result */
10973     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oType);
10974     RegOperand *iOpnd = &CreateRegisterOperandOfType(oType); /* float intermediate result */
10975     uint32 eSize = GetVecEleSize(oType);                     /* vector opd in bits */
10976     bool is16ByteVec = GetPrimTypeSize(oType) >= k16ByteSize;
10977     MOperator mOp;
10978     if (is16ByteVec) {
10979         mOp = eSize <= k8BitSize
10980                   ? MOP_vbaddvrv
10981                   : (eSize <= k16BitSize ? MOP_vhaddvrv : (eSize <= k32BitSize ? MOP_vsaddvrv : MOP_vdaddvrv));
10982     } else {
10983         mOp = eSize <= k8BitSize ? MOP_vbaddvru : (eSize <= k16BitSize ? MOP_vhaddvru : MOP_vsaddvru);
10984     }
10985     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10986     vInsn.AddOpndChain(*iOpnd).AddOpndChain(*o1);
10987     vInsn.PushRegSpecEntry(vecSpec1);
10988     GetCurBB()->AppendInsn(vInsn);
10989 
10990     mOp = eSize > k32BitSize ? MOP_vxmovrv : MOP_vwmovrv;
10991     VectorInsn &vInsn2 = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
10992     auto *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oType);
10993     vInsn2.AddOpndChain(*res).AddOpndChain(*iOpnd);
10994     vecSpec2->vecLane = 0;
10995     vInsn2.PushRegSpecEntry(vecSpec2);
10996     GetCurBB()->AppendInsn(vInsn2);
10997     return res;
10998 }
10999 
PrepareVectorOperands(Operand ** o1,PrimType & oty1,Operand ** o2,PrimType & oty2)11000 void AArch64CGFunc::PrepareVectorOperands(Operand **o1, PrimType &oty1, Operand **o2, PrimType &oty2)
11001 {
11002     /* Only 1 operand can be non vector, otherwise it's a scalar operation, wouldn't come here */
11003     if (IsPrimitiveVector(oty1) == IsPrimitiveVector(oty2)) {
11004         return;
11005     }
11006     PrimType origTyp = !IsPrimitiveVector(oty2) ? oty2 : oty1;
11007     Operand *opd = !IsPrimitiveVector(oty2) ? *o2 : *o1;
11008     PrimType rType = !IsPrimitiveVector(oty2) ? oty1 : oty2; /* Type to dup into */
11009     RegOperand *res = &CreateRegisterOperandOfType(rType);
11010     VectorRegSpec *vecSpec = GetMemoryPool()->New<VectorRegSpec>(rType);
11011 
11012     bool immOpnd = false;
11013     if (opd->IsConstImmediate()) {
11014         int64 val = static_cast<ImmOperand *>(opd)->GetValue();
11015         if (val >= kMinImmVal && val <= kMaxImmVal && GetVecEleSize(rType) < k64BitSize) {
11016             immOpnd = true;
11017         } else {
11018             RegOperand *regOpd = &CreateRegisterOperandOfType(origTyp);
11019             SelectCopyImm(*regOpd, origTyp, static_cast<ImmOperand &>(*opd), origTyp);
11020             opd = static_cast<Operand *>(regOpd);
11021         }
11022     }
11023 
11024     /* need dup to vector operand */
11025     MOperator mOp;
11026     if (immOpnd) {
11027         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vmovvi : MOP_vmovui; /* a const */
11028     } else {
11029         if (GetPrimTypeSize(origTyp) > k4ByteSize) {
11030             mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vxdupvr : MOP_vxdupur;
11031         } else {
11032             mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vwdupvr : MOP_vwdupur; /* a scalar var */
11033         }
11034     }
11035     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11036     vInsn.AddOpndChain(*res).AddOpndChain(*opd);
11037     vInsn.PushRegSpecEntry(vecSpec);
11038     GetCurBB()->AppendInsn(vInsn);
11039     if (!IsPrimitiveVector(oty2)) {
11040         *o2 = static_cast<Operand *>(res);
11041         oty2 = rType;
11042     } else {
11043         *o1 = static_cast<Operand *>(res);
11044         oty1 = rType;
11045     }
11046 }
11047 
SelectVectorCvt(Operand * res,PrimType rType,Operand * o1,PrimType oType)11048 void AArch64CGFunc::SelectVectorCvt(Operand *res, PrimType rType, Operand *o1, PrimType oType)
11049 {
11050     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11051     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oType); /* vector operand 1 */
11052 
11053     MOperator mOp;
11054     VectorInsn *insn;
11055     if (GetPrimTypeSize(rType) > GetPrimTypeSize(oType)) {
11056         /* expand, similar to vmov_XX() intrinsics */
11057         mOp = IsUnsignedInteger(rType) ? MOP_vushllvvi : MOP_vshllvvi;
11058         ImmOperand *imm = &CreateImmOperand(0, k8BitSize, true);
11059         insn = &GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11060         insn->AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*imm);
11061     } else if (GetPrimTypeSize(rType) < GetPrimTypeSize(oType)) {
11062         /* extract, similar to vqmovn_XX() intrinsics */
11063         insn = &GetInsnBuilder()->BuildVectorInsn(MOP_vxtnuv, AArch64CG::kMd[MOP_vxtnuv]);
11064         insn->AddOpndChain(*res).AddOpndChain(*o1);
11065     } else {
11066         CHECK_FATAL(0, "Invalid cvt between 2 operands of the same size");
11067     }
11068     insn->PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
11069     GetCurBB()->AppendInsn(*insn);
11070 }
11071 
SelectVectorCompareZero(Operand * o1,PrimType oty1,Operand * o2,Opcode opc)11072 RegOperand *AArch64CGFunc::SelectVectorCompareZero(Operand *o1, PrimType oty1, Operand *o2, Opcode opc)
11073 {
11074     if (IsUnsignedInteger(oty1) && (opc != OP_eq && opc != OP_ne)) {
11075         return nullptr; /* no unsigned instr for zero */
11076     }
11077     RegOperand *res = &CreateRegisterOperandOfType(oty1); /* result operand */
11078     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(oty1);
11079     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oty1); /* vector operand 1 */
11080 
11081     MOperator mOp;
11082     switch (opc) {
11083         case OP_eq:
11084         case OP_ne:
11085             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vzcmeqvv : MOP_vzcmequu;
11086             break;
11087         case OP_gt:
11088             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vzcmgtvv : MOP_vzcmgtuu;
11089             break;
11090         case OP_ge:
11091             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vzcmgevv : MOP_vzcmgeuu;
11092             break;
11093         case OP_lt:
11094             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vzcmltvv : MOP_vzcmltuu;
11095             break;
11096         case OP_le:
11097             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vzcmlevv : MOP_vzcmleuu;
11098             break;
11099         default:
11100             CHECK_FATAL(0, "Invalid cc in vector compare");
11101     }
11102     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11103     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11104     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
11105     GetCurBB()->AppendInsn(vInsn);
11106     if (opc == OP_ne) {
11107         res = SelectVectorNot(oty1, res);
11108     }
11109     return res;
11110 }
11111 
11112 /* Neon compare intrinsics always return unsigned vector, MapleIR for comparison always return
11113    signed.  Using type of 1st operand for operation here */
SelectVectorCompare(Operand * o1,PrimType oty1,Operand * o2,PrimType oty2,Opcode opc)11114 RegOperand *AArch64CGFunc::SelectVectorCompare(Operand *o1, PrimType oty1, Operand *o2, PrimType oty2, Opcode opc)
11115 {
11116     if (o2->IsConstImmediate() && static_cast<ImmOperand *>(o2)->GetValue() == 0) {
11117         RegOperand *zeroCmp = SelectVectorCompareZero(o1, oty1, o2, opc);
11118         if (zeroCmp != nullptr) {
11119             return zeroCmp;
11120         }
11121     }
11122     PrepareVectorOperands(&o1, oty1, &o2, oty2);
11123     DEBUG_ASSERT(oty1 == oty2, "vector operand type mismatch");
11124 
11125     RegOperand *res = &CreateRegisterOperandOfType(oty1); /* result operand */
11126     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(oty1);
11127     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oty1); /* vector operand 1 */
11128     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oty2); /* vector operand 2 */
11129 
11130     MOperator mOp;
11131     switch (opc) {
11132         case OP_eq:
11133         case OP_ne:
11134             mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vcmeqvvv : MOP_vcmequuu;
11135             break;
11136         case OP_lt:
11137         case OP_gt:
11138             if (IsUnsignedInteger(oty1)) {
11139                 mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vcmhivvv : MOP_vcmhiuuu;
11140             } else {
11141                 mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vcmgtvvv : MOP_vcmgtuuu;
11142             }
11143             break;
11144         case OP_le:
11145         case OP_ge:
11146             if (IsUnsignedInteger(oty1)) {
11147                 mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vcmhsvvv : MOP_vcmhsuuu;
11148             } else {
11149                 mOp = GetPrimTypeSize(oty1) > k8ByteSize ? MOP_vcmgevvv : MOP_vcmgeuuu;
11150             }
11151             break;
11152         default:
11153             CHECK_FATAL(0, "Invalid cc in vector compare");
11154     }
11155     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11156     if (opc == OP_lt || opc == OP_le) {
11157         vInsn.AddOpndChain(*res).AddOpndChain(*o2).AddOpndChain(*o1);
11158     } else {
11159         vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11160     }
11161     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11162     GetCurBB()->AppendInsn(vInsn);
11163     if (opc == OP_ne) {
11164         res = SelectVectorNot(oty1, res);
11165     }
11166     return res;
11167 }
11168 
SelectVectorShift(PrimType rType,Operand * o1,PrimType oty1,Operand * o2,PrimType oty2,Opcode opc)11169 RegOperand *AArch64CGFunc::SelectVectorShift(PrimType rType, Operand *o1, PrimType oty1, Operand *o2, PrimType oty2,
11170                                              Opcode opc)
11171 {
11172     PrepareVectorOperands(&o1, oty1, &o2, oty2);
11173     PrimType resultType = rType;
11174     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11175     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11176     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 2 */
11177 
11178     if (!IsPrimitiveVector(rType)) {
11179         o1 = &SelectCopy(*o1, rType, PTY_f64);
11180         o2 = &SelectCopy(*o2, rType, PTY_f64);
11181         resultType = PTY_f64;
11182     }
11183     RegOperand *res = &CreateRegisterOperandOfType(resultType); /* result operand */
11184 
11185     /* signed and unsigned shl(v,v) both use sshl or ushl, they are the same */
11186     MOperator mOp;
11187     if (IsPrimitiveUnsigned(rType)) {
11188         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vushlvvv : MOP_vushluuu;
11189     } else {
11190         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vshlvvv : MOP_vshluuu;
11191     }
11192 
11193     if (opc != OP_shl) {
11194         o2 = SelectVectorNeg(rType, o2);
11195     }
11196     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11197     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11198     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11199     GetCurBB()->AppendInsn(vInsn);
11200     return res;
11201 }
11202 
ValidShiftConst(PrimType rType)11203 uint32 ValidShiftConst(PrimType rType)
11204 {
11205     switch (rType) {
11206         case PTY_v8u8:
11207         case PTY_v8i8:
11208         case PTY_v16u8:
11209         case PTY_v16i8:
11210             return k8BitSize;
11211         case PTY_v4u16:
11212         case PTY_v4i16:
11213         case PTY_v8u16:
11214         case PTY_v8i16:
11215             return k16BitSize;
11216         case PTY_v2u32:
11217         case PTY_v2i32:
11218         case PTY_v4u32:
11219         case PTY_v4i32:
11220             return k32BitSize;
11221         case PTY_v2u64:
11222         case PTY_v2i64:
11223             return k64BitSize;
11224         default:
11225             CHECK_FATAL(0, "Invalid Shift operand type");
11226     }
11227     return 0;
11228 }
11229 
SelectVectorShiftImm(PrimType rType,Operand * o1,Operand * imm,int32 sVal,Opcode opc)11230 RegOperand *AArch64CGFunc::SelectVectorShiftImm(PrimType rType, Operand *o1, Operand *imm, int32 sVal, Opcode opc)
11231 {
11232     auto resultType = FilterOneElementVectorType(rType);
11233     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11234     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11235     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11236 
11237     if (!imm->IsConstImmediate()) {
11238         CHECK_FATAL(0, "VectorUShiftImm has invalid shift const");
11239     }
11240     uint32 shift = static_cast<uint32>(ValidShiftConst(rType));
11241     bool needDup = false;
11242     if (opc == OP_shl) {
11243         if ((shift == k8BitSize && (sVal < 0 || static_cast<uint32>(sVal) >= shift)) ||
11244             (shift == k16BitSize && (sVal < 0 || static_cast<uint32>(sVal) >= shift)) ||
11245             (shift == k32BitSize && (sVal < 0 || static_cast<uint32>(sVal) >= shift)) ||
11246             (shift == k64BitSize && (sVal < 0 || static_cast<uint32>(sVal) >= shift))) {
11247             needDup = true;
11248         }
11249     } else {
11250         if ((shift == k8BitSize && (sVal < 1 || static_cast<uint32>(sVal) > shift)) ||
11251             (shift == k16BitSize && (sVal < 1 || static_cast<uint32>(sVal) > shift)) ||
11252             (shift == k32BitSize && (sVal < 1 || static_cast<uint32>(sVal) > shift)) ||
11253             (shift == k64BitSize && (sVal < 1 || static_cast<uint32>(sVal) > shift))) {
11254             needDup = true;
11255         }
11256     }
11257     if (needDup) {
11258         /* Dup constant to vector reg */
11259         SelectCopy(*res, resultType, *imm, imm->GetSize() == k64BitSize ? PTY_u64 : PTY_u32);
11260         res = SelectVectorShift(rType, o1, rType, res, rType, opc);
11261         return res;
11262     }
11263     MOperator mOp;
11264     if (GetPrimTypeSize(rType) > k8ByteSize) {
11265         if (IsUnsignedInteger(rType)) {
11266             mOp = opc == OP_shl ? MOP_vushlvvi : MOP_vushrvvi;
11267         } else {
11268             mOp = opc == OP_shl ? MOP_vushlvvi : MOP_vshrvvi;
11269         }
11270     } else {
11271         if (IsUnsignedInteger(rType)) {
11272             mOp = opc == OP_shl ? MOP_vushluui : MOP_vushruui;
11273         } else {
11274             mOp = opc == OP_shl ? MOP_vushluui : MOP_vshruui;
11275         }
11276     }
11277     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11278     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*imm);
11279     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
11280     GetCurBB()->AppendInsn(vInsn);
11281     return res;
11282 }
11283 
SelectVectorTableLookup(PrimType rType,Operand * o1,Operand * o2)11284 RegOperand *AArch64CGFunc::SelectVectorTableLookup(PrimType rType, Operand *o1, Operand *o2)
11285 {
11286     RegOperand *res = &CreateRegisterOperandOfType(rType);                   /* result operand */
11287     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType); /* 8B or 16B */
11288     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType);    /* vector operand 1 */
11289     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(rType);    /* vector operand 2 */
11290     vecSpec1->compositeOpnds = 1;                                            /* composite operand */
11291 
11292     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(MOP_vtbl1vvv, AArch64CG::kMd[MOP_vtbl1vvv]);
11293     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11294     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11295     GetCurBB()->AppendInsn(vInsn);
11296     return res;
11297 }
11298 
SelectVectorMadd(Operand * o1,PrimType oTyp1,Operand * o2,PrimType oTyp2,Operand * o3,PrimType oTyp3)11299 RegOperand *AArch64CGFunc::SelectVectorMadd(Operand *o1, PrimType oTyp1, Operand *o2, PrimType oTyp2, Operand *o3,
11300                                             PrimType oTyp3)
11301 {
11302     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oTyp1); /* operand 1 and result */
11303     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oTyp2); /* vector operand 2 */
11304     VectorRegSpec *vecSpec3 = GetMemoryPool()->New<VectorRegSpec>(oTyp3); /* vector operand 2 */
11305 
11306     MOperator mop = IsPrimitiveUnSignedVector(oTyp1) ? MOP_vumaddvvv : MOP_vsmaddvvv;
11307     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
11308     vInsn.AddOpndChain(*o1).AddOpndChain(*o2).AddOpndChain(*o3);
11309     vInsn.PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2).PushRegSpecEntry(vecSpec3);
11310     GetCurBB()->AppendInsn(vInsn);
11311     return static_cast<RegOperand *>(o1);
11312 }
11313 
SelectVectorMull(PrimType rType,Operand * o1,PrimType oTyp1,Operand * o2,PrimType oTyp2,bool isLow)11314 RegOperand *AArch64CGFunc::SelectVectorMull(PrimType rType, Operand *o1, PrimType oTyp1, Operand *o2, PrimType oTyp2,
11315                                             bool isLow)
11316 {
11317     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11318     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11319     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oTyp1); /* vector operand 1 */
11320     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oTyp2); /* vector operand 1 */
11321 
11322     MOperator mop;
11323     if (isLow) {
11324         mop = IsPrimitiveUnSignedVector(rType) ? MOP_vumullvvv : MOP_vsmullvvv;
11325     } else {
11326         mop = IsPrimitiveUnSignedVector(rType) ? MOP_vumull2vvv : MOP_vsmull2vvv;
11327     }
11328     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mop, AArch64CG::kMd[mop]);
11329     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11330     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11331     GetCurBB()->AppendInsn(vInsn);
11332     return res;
11333 }
11334 
SelectVectorBinOp(PrimType rType,Operand * o1,PrimType oty1,Operand * o2,PrimType oty2,Opcode opc)11335 RegOperand *AArch64CGFunc::SelectVectorBinOp(PrimType rType, Operand *o1, PrimType oty1, Operand *o2, PrimType oty2,
11336                                              Opcode opc)
11337 {
11338     PrepareVectorOperands(&o1, oty1, &o2, oty2);
11339     DEBUG_ASSERT(oty1 == oty2, "vector operand type mismatch");
11340 
11341     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11342     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11343     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oty1); /* source operand 1 */
11344     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oty2); /* source operand 2 */
11345 
11346     MOperator mOp;
11347     if (opc == OP_add) {
11348         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vaddvvv : MOP_vadduuu;
11349     } else if (opc == OP_sub) {
11350         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vsubvvv : MOP_vsubuuu;
11351     } else if (opc == OP_mul) {
11352         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vmulvvv : MOP_vmuluuu;
11353     } else {
11354         CHECK_FATAL(0, "Invalid opcode for SelectVectorBinOp");
11355     }
11356     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11357     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11358     /* dest pushed first, popped first */
11359     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11360     GetCurBB()->AppendInsn(vInsn);
11361     return res;
11362 }
11363 
SelectVectorBitwiseOp(PrimType rType,Operand * o1,PrimType oty1,Operand * o2,PrimType oty2,Opcode opc)11364 RegOperand *AArch64CGFunc::SelectVectorBitwiseOp(PrimType rType, Operand *o1, PrimType oty1, Operand *o2, PrimType oty2,
11365                                                  Opcode opc)
11366 {
11367     PrepareVectorOperands(&o1, oty1, &o2, oty2);
11368     DEBUG_ASSERT(oty1 == oty2, "vector operand type mismatch");
11369 
11370     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11371     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11372     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11373     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11374 
11375     MOperator mOp;
11376     if (opc == OP_band) {
11377         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vandvvv : MOP_vanduuu;
11378     } else if (opc == OP_bior) {
11379         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vorvvv : MOP_voruuu;
11380     } else if (opc == OP_bxor) {
11381         mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vxorvvv : MOP_vxoruuu;
11382     } else {
11383         CHECK_FATAL(0, "Invalid opcode for SelectVectorBitwiseOp");
11384     }
11385     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11386     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11387     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2);
11388     GetCurBB()->AppendInsn(vInsn);
11389     return res;
11390 }
11391 
SelectVectorNarrow(PrimType rType,Operand * o1,PrimType otyp)11392 RegOperand *AArch64CGFunc::SelectVectorNarrow(PrimType rType, Operand *o1, PrimType otyp)
11393 {
11394     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11395     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11396     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(otyp); /* vector operand */
11397 
11398     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(MOP_vxtnuv, AArch64CG::kMd[MOP_vxtnuv]);
11399     vInsn.AddOpndChain(*res).AddOpndChain(*o1);
11400     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
11401     GetCurBB()->AppendInsn(vInsn);
11402     return res;
11403 }
11404 
SelectVectorNarrow2(PrimType rType,Operand * o1,PrimType oty1,Operand * o2,PrimType oty2)11405 RegOperand *AArch64CGFunc::SelectVectorNarrow2(PrimType rType, Operand *o1, PrimType oty1, Operand *o2, PrimType oty2)
11406 {
11407     (void)oty1;                                      /* 1st opnd was loaded already, type no longer needed */
11408     RegOperand *res = static_cast<RegOperand *>(o1); /* o1 is also the result */
11409     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11410     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(oty2); /* vector opnd2 */
11411 
11412     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(MOP_vxtn2uv, AArch64CG::kMd[MOP_vxtn2uv]);
11413     vInsn.AddOpndChain(*res).AddOpndChain(*o2);
11414     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec2);
11415     GetCurBB()->AppendInsn(vInsn);
11416     return res;
11417 }
11418 
SelectVectorNot(PrimType rType,Operand * o1)11419 RegOperand *AArch64CGFunc::SelectVectorNot(PrimType rType, Operand *o1)
11420 {
11421     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11422     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11423     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11424 
11425     MOperator mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vnotvv : MOP_vnotuu;
11426     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11427     vInsn.AddOpndChain(*res).AddOpndChain(*o1);
11428     vInsn.PushRegSpecEntry(vecSpecDest).PushRegSpecEntry(vecSpec1);
11429     GetCurBB()->AppendInsn(vInsn);
11430     return res;
11431 }
11432 
SelectVectorNeg(PrimType rType,Operand * o1)11433 RegOperand *AArch64CGFunc::SelectVectorNeg(PrimType rType, Operand *o1)
11434 {
11435     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11436     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11437     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11438 
11439     MOperator mOp = GetPrimTypeSize(rType) > k8ByteSize ? MOP_vnegvv : MOP_vneguu;
11440     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11441     vInsn.AddOpndChain(*res).AddOpndChain(*o1);
11442     vInsn.PushRegSpecEntry(vecSpecDest);
11443     vInsn.PushRegSpecEntry(vecSpec1);
11444     GetCurBB()->AppendInsn(vInsn);
11445     return res;
11446 }
11447 
11448 /*
11449  * Called internally for auto-vec, no intrinsics for now
11450  */
SelectVectorSelect(Operand & cond,PrimType rType,Operand & o0,Operand & o1)11451 RegOperand *AArch64CGFunc::SelectVectorSelect(Operand &cond, PrimType rType, Operand &o0, Operand &o1)
11452 {
11453     rType = GetPrimTypeSize(rType) > k8ByteSize ? PTY_v16u8 : PTY_v8u8;
11454     RegOperand *res = &CreateRegisterOperandOfType(rType);
11455     SelectCopy(*res, rType, cond, rType);
11456     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11457     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType);
11458     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(rType);
11459 
11460     uint32 mOp = GetPrimTypeBitSize(rType) > k64BitSize ? MOP_vbslvvv : MOP_vbsluuu;
11461     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11462     vInsn.AddOpndChain(*res).AddOpndChain(o0).AddOpndChain(o1);
11463     vInsn.PushRegSpecEntry(vecSpecDest);
11464     vInsn.PushRegSpecEntry(vecSpec1);
11465     vInsn.PushRegSpecEntry(vecSpec2);
11466     GetCurBB()->AppendInsn(vInsn);
11467     return res;
11468 }
11469 
SelectVectorShiftRNarrow(PrimType rType,Operand * o1,PrimType oType,Operand * o2,bool isLow)11470 RegOperand *AArch64CGFunc::SelectVectorShiftRNarrow(PrimType rType, Operand *o1, PrimType oType, Operand *o2,
11471                                                     bool isLow)
11472 {
11473     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11474     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11475     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(oType); /* vector operand 1 */
11476 
11477     ImmOperand *imm = static_cast<ImmOperand *>(o2);
11478     MOperator mOp;
11479     if (isLow) {
11480         mOp = MOP_vshrnuvi;
11481     } else {
11482         CHECK_FATAL(0, "NYI: vshrn_high_");
11483     }
11484     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11485     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*imm);
11486     vInsn.PushRegSpecEntry(vecSpecDest);
11487     vInsn.PushRegSpecEntry(vecSpec1);
11488     GetCurBB()->AppendInsn(vInsn);
11489     return res;
11490 }
11491 
SelectVectorSubWiden(PrimType resType,Operand * o1,PrimType otyp1,Operand * o2,PrimType otyp2,bool isLow,bool isWide)11492 RegOperand *AArch64CGFunc::SelectVectorSubWiden(PrimType resType, Operand *o1, PrimType otyp1, Operand *o2,
11493                                                 PrimType otyp2, bool isLow, bool isWide)
11494 {
11495     RegOperand *res = &CreateRegisterOperandOfType(resType); /* result reg */
11496     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(resType);
11497     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(otyp1); /* vector operand 1 */
11498     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(otyp2); /* vector operand 2 */
11499 
11500     MOperator mOp;
11501     if (!isWide) {
11502         if (isLow) {
11503             mOp = IsUnsignedInteger(otyp1) ? MOP_vusublvuu : MOP_vssublvuu;
11504         } else {
11505             mOp = IsUnsignedInteger(otyp1) ? MOP_vusubl2vvv : MOP_vssubl2vvv;
11506         }
11507     } else {
11508         if (isLow) {
11509             mOp = IsUnsignedInteger(otyp1) ? MOP_vusubwvvu : MOP_vssubwvvu;
11510         } else {
11511             mOp = IsUnsignedInteger(otyp1) ? MOP_vusubw2vvv : MOP_vssubw2vvv;
11512         }
11513     }
11514     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11515     vInsn.AddOpndChain(*res).AddOpndChain(*o1).AddOpndChain(*o2);
11516     vInsn.PushRegSpecEntry(vecSpecDest);
11517     vInsn.PushRegSpecEntry(vecSpec1);
11518     vInsn.PushRegSpecEntry(vecSpec2);
11519     GetCurBB()->AppendInsn(vInsn);
11520     return res;
11521 }
11522 
SelectVectorZip(PrimType rType,Operand * o1,Operand * o2)11523 void AArch64CGFunc::SelectVectorZip(PrimType rType, Operand *o1, Operand *o2)
11524 {
11525     RegOperand *res1 = &CreateRegisterOperandOfType(rType); /* result operand 1 */
11526     RegOperand *res2 = &CreateRegisterOperandOfType(rType); /* result operand 2 */
11527     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11528     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 1 */
11529     VectorRegSpec *vecSpec2 = GetMemoryPool()->New<VectorRegSpec>(rType); /* vector operand 2 */
11530 
11531     VectorInsn &vInsn1 = GetInsnBuilder()->BuildVectorInsn(MOP_vzip1vvv, AArch64CG::kMd[MOP_vzip1vvv]);
11532     vInsn1.AddOpndChain(*res1).AddOpndChain(*o1).AddOpndChain(*o2);
11533     vInsn1.PushRegSpecEntry(vecSpecDest);
11534     vInsn1.PushRegSpecEntry(vecSpec1);
11535     vInsn1.PushRegSpecEntry(vecSpec2);
11536     GetCurBB()->AppendInsn(vInsn1);
11537 
11538     VectorInsn &vInsn2 = GetInsnBuilder()->BuildVectorInsn(MOP_vzip2vvv, AArch64CG::kMd[MOP_vzip2vvv]);
11539     vInsn2.AddOpndChain(*res2).AddOpndChain(*o1).AddOpndChain(*o2);
11540     vInsn2.PushRegSpecEntry(vecSpecDest);
11541     vInsn2.PushRegSpecEntry(vecSpec1);
11542     vInsn2.PushRegSpecEntry(vecSpec2);
11543     GetCurBB()->AppendInsn(vInsn2);
11544 
11545     if (GetPrimTypeSize(rType) <= k16ByteSize) {
11546         Operand *preg1 = &GetOrCreatePhysicalRegisterOperand(V0, k64BitSize, kRegTyFloat);
11547         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xvmovd, *preg1, *res1));
11548         Operand *preg2 = &GetOrCreatePhysicalRegisterOperand(V1, k64BitSize, kRegTyFloat);
11549         GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xvmovd, *preg2, *res2));
11550     }
11551 }
11552 
SelectVectorWiden(PrimType rType,Operand * o1,PrimType otyp,bool isLow)11553 RegOperand *AArch64CGFunc::SelectVectorWiden(PrimType rType, Operand *o1, PrimType otyp, bool isLow)
11554 {
11555     RegOperand *res = &CreateRegisterOperandOfType(rType); /* result operand */
11556     VectorRegSpec *vecSpecDest = GetMemoryPool()->New<VectorRegSpec>(rType);
11557     VectorRegSpec *vecSpec1 = GetMemoryPool()->New<VectorRegSpec>(otyp); /* vector operand */
11558 
11559     MOperator mOp;
11560     if (isLow) {
11561         mOp = IsPrimitiveUnSignedVector(rType) ? MOP_vuxtlvu : MOP_vsxtlvu;
11562     } else {
11563         mOp = IsPrimitiveUnSignedVector(rType) ? MOP_vuxtl2vv : MOP_vsxtl2vv;
11564     }
11565     VectorInsn &vInsn = GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]);
11566     vInsn.AddOpndChain(*res).AddOpndChain(*o1);
11567     vInsn.PushRegSpecEntry(vecSpecDest);
11568     vInsn.PushRegSpecEntry(vecSpec1);
11569     GetCurBB()->AppendInsn(vInsn);
11570     return res;
11571 }
11572 
11573 /* Check the distance between the first insn of BB with the lable(targ_labidx)
11574  * and the insn with targ_id. If the distance greater than maxDistance
11575  * return false.
11576  */
DistanceCheck(const BB & bb,LabelIdx targLabIdx,uint32 targId,uint32 maxDistance) const11577 bool AArch64CGFunc::DistanceCheck(const BB &bb, LabelIdx targLabIdx, uint32 targId, uint32 maxDistance) const
11578 {
11579     for (auto *tBB : bb.GetSuccs()) {
11580         if (tBB->GetLabIdx() != targLabIdx) {
11581             continue;
11582         }
11583         Insn *tInsn = tBB->GetFirstInsn();
11584         while (tInsn == nullptr || !tInsn->IsMachineInstruction()) {
11585             if (tInsn == nullptr) {
11586                 tBB = tBB->GetNext();
11587                 if (tBB == nullptr) { /* tailcallopt may make the target block empty */
11588                     return true;
11589                 }
11590                 tInsn = tBB->GetFirstInsn();
11591             } else {
11592                 tInsn = tInsn->GetNext();
11593             }
11594         }
11595         uint32 tmp = (tInsn->GetId() > targId) ? (tInsn->GetId() - targId) : (targId - tInsn->GetId());
11596         return (tmp < maxDistance);
11597     }
11598     CHECK_FATAL(false, "CFG error");
11599 }
11600 
SplitInt128(Operand & opnd)11601 AArch64CGFunc::SplittedInt128 AArch64CGFunc::SplitInt128(Operand &opnd)
11602 {
11603     DEBUG_ASSERT(opnd.IsRegister(), "expected register opnd");
11604     auto vecTy = PTY_v2u64;
11605     auto scTy = PTY_u64;
11606     Operand &low = *SelectVectorGetElement(scTy, &opnd, vecTy, 0);
11607     Operand &high = *SelectVectorGetElement(scTy, &opnd, vecTy, 1);
11608     return {low, high};
11609 }
11610 
CombineInt128(const SplittedInt128 parts)11611 RegOperand &AArch64CGFunc::CombineInt128(const SplittedInt128 parts)
11612 {
11613     RegOperand &resOpnd = CreateRegisterOperandOfType(PTY_v2u64);
11614     CombineInt128(resOpnd, parts);
11615     return resOpnd;
11616 }
11617 
CombineInt128(Operand & resOpnd,const SplittedInt128 parts)11618 void AArch64CGFunc::CombineInt128(Operand &resOpnd, const SplittedInt128 parts)
11619 {
11620     auto vecTy = PTY_v2u64;
11621     auto scTy = PTY_u64;
11622     auto *tmpOpnd = SelectVectorFromScalar(vecTy, &parts.low, scTy);
11623     SelectCopy(resOpnd, vecTy, *SelectVectorSetElement(&parts.high, scTy, tmpOpnd, vecTy, 1), vecTy);
11624 }
11625 
SelectParmListForInt128(Operand & opnd,ListOperand & srcOpnds,const CCLocInfo & ploc,bool isSpecialArg,std::vector<RegMapForPhyRegCpy> & regMapForTmpBB)11626 void AArch64CGFunc::SelectParmListForInt128(Operand &opnd, ListOperand &srcOpnds, const CCLocInfo &ploc,
11627                                             bool isSpecialArg, std::vector<RegMapForPhyRegCpy> &regMapForTmpBB)
11628 {
11629     DEBUG_ASSERT(ploc.reg0 != kRinvalid && ploc.reg1 != kRinvalid, "");
11630 
11631     auto splitOpnd = SplitInt128(opnd);
11632     auto reg0 = static_cast<AArch64reg>(ploc.reg0);
11633     auto reg1 = static_cast<AArch64reg>(ploc.reg1);
11634     RegOperand &low = GetOrCreatePhysicalRegisterOperand(reg0, k64BitSize, kRegTyInt);
11635     RegOperand &high = GetOrCreatePhysicalRegisterOperand(reg1, k64BitSize, kRegTyInt);
11636 
11637     auto cpyTy = PTY_u64;
11638     if (isSpecialArg) {
11639         regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&low, cpyTy, static_cast<RegOperand *>(&splitOpnd.low), cpyTy));
11640         regMapForTmpBB.emplace_back(
11641             RegMapForPhyRegCpy(&high, cpyTy, static_cast<RegOperand *>(&splitOpnd.high), cpyTy));
11642     } else {
11643         SelectCopy(low, cpyTy, splitOpnd.low, cpyTy);
11644         SelectCopy(high, cpyTy, splitOpnd.high, cpyTy);
11645     }
11646 
11647     srcOpnds.PushOpnd(low);
11648     srcOpnds.PushOpnd(high);
11649 }
11650 } /* namespace maplebe */
11651