• 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 #ifndef MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_CGFUNC_H
17 #define MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_CGFUNC_H
18 
19 #include "cgfunc.h"
20 #include "call_conv.h"
21 #include "aarch64_abi.h"
22 #include "aarch64_operand.h"
23 #include "aarch64_insn.h"
24 #include "aarch64_memlayout.h"
25 #include "aarch64_reg_info.h"
26 #include "aarch64_optimize_common.h"
27 #include "aarch64_call_conv.h"
28 
29 namespace maplebe {
30 class AArch64CGFunc : public CGFunc {
31 public:
AArch64CGFunc(MIRModule & mod,CG & c,MIRFunction & f,BECommon & b,MemPool & memPool,StackMemPool & stackMp,MapleAllocator & mallocator,uint32 funcId)32     AArch64CGFunc(MIRModule &mod, CG &c, MIRFunction &f, BECommon &b, MemPool &memPool, StackMemPool &stackMp,
33                   MapleAllocator &mallocator, uint32 funcId)
34         : CGFunc(mod, c, f, b, memPool, stackMp, mallocator, funcId),
35           calleeSavedRegs(mallocator.Adapter()),
36           proEpilogSavedRegs(mallocator.Adapter()),
37           phyRegOperandTable(mallocator.Adapter()),
38           hashLabelOpndTable(mallocator.Adapter()),
39           hashOfstOpndTable(mallocator.Adapter()),
40           hashMemOpndTable(mallocator.Adapter()),
41           memOpndsRequiringOffsetAdjustment(mallocator.Adapter()),
42           memOpndsForStkPassedArguments(mallocator.Adapter()),
43           immOpndsRequiringOffsetAdjustment(mallocator.Adapter()),
44           immOpndsRequiringOffsetAdjustmentForRefloc(mallocator.Adapter()),
45           hashCCTable(mallocator.Adapter())
46     {
47         CGFunc::SetMemlayout(*memPool.New<AArch64MemLayout>(b, f, mallocator));
48         CGFunc::GetMemlayout()->SetCurrFunction(*this);
49         CGFunc::SetTargetRegInfo(*memPool.New<AArch64RegInfo>(mallocator));
50         CGFunc::GetTargetRegInfo()->SetCurrFunction(*this);
51         if (f.GetAttr(FUNCATTR_varargs) || f.HasVlaOrAlloca()) {
52             SetHasVLAOrAlloca(true);
53         }
54         SetHasAlloca(f.HasVlaOrAlloca());
55         SetUseFP(true);
56     }
57 
58     ~AArch64CGFunc() override = default;
59 
60     MOperator PickMovBetweenRegs(PrimType destType, PrimType srcType) const;
61 
NewVRflag()62     regno_t NewVRflag() override
63     {
64         DEBUG_ASSERT(GetMaxRegNum() > kRFLAG, "CG internal error.");
65         constexpr uint8 size = 4;
66         if (GetMaxRegNum() <= kRFLAG) {
67             IncMaxRegNum(kRFLAG + kVRegisterNumber);
68             vReg.VRegTableResize(GetMaxRegNum());
69         }
70         vReg.VRegTableValuesSet(kRFLAG, kRegTyCc, size);
71         return kRFLAG;
72     }
73 
74     CCImpl *GetOrCreateLocator(CallConvKind cc);
75     RegOperand &GetOrCreateResOperand(const BaseNode &parent, PrimType primType);
76 
77     // struct for delayed phy regs copy in param list
78     struct RegMapForPhyRegCpy {
RegMapForPhyRegCpyRegMapForPhyRegCpy79         RegMapForPhyRegCpy(RegOperand *dReg, PrimType dType, RegOperand *sReg, PrimType sType)
80             : destReg(dReg), destType(dType), srcReg(sReg), srcType(sType)
81         {
82         }
83         RegOperand *destReg;
84         PrimType destType;
85         RegOperand *srcReg;
86         PrimType srcType;
87     };
88 
89     void MergeReturn() override;
90     void SelectDassign(DassignNode &stmt, Operand &opnd0) override;
91     void SelectRegassign(RegassignNode &stmt, Operand &opnd0) override;
92     void SelectIassign(IassignNode &stmt) override;
93     void SelectReturn(Operand *opnd0) override;
94     bool DoCallerEnsureValidParm(RegOperand &destOpnd, RegOperand &srcOpnd, PrimType formalPType);
95     void SelectParmListPassByStack(const MIRType &mirType, Operand &opnd, uint32 memOffset, bool preCopyed,
96                                    std::vector<Insn *> &insnForStackArgs);
97     void SelectCondGoto(CondGotoNode &stmt, Operand &opnd0, Operand &opnd1) override;
98     void SelectCondGoto(LabelOperand &targetOpnd, Opcode jmpOp, Opcode cmpOp, Operand &opnd0, Operand &opnd1,
99                         PrimType primType, bool signedCond);
100     void SelectCondSpecialCase1(CondGotoNode &stmt, BaseNode &opnd0) override;
101     void SelectCondSpecialCase2(const CondGotoNode &stmt, BaseNode &opnd0) override;
102     void SelectGoto(GotoNode &stmt) override;
103     void SelectCall(CallNode &callNode) override;
104     void SelectIcall(IcallNode &icallNode) override;
105     void SelectIntrinsicCall(IntrinsiccallNode &intrinsicCallNode) override;
106     void SelectDeoptCall(CallNode &callNode) override;
107     void SelectTailICall(IcallNode &icallNode) override;
108     Operand *SelectCclz(IntrinsicopNode &intrinsicopNode) override;
109     RegOperand *SelectHeapConstant(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1) override;
110     RegOperand *SelectTaggedIsHeapObject(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1) override;
111     RegOperand *SelectIsStableElements(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1, Operand &opnd2) override;
112     RegOperand *SelectHasPendingException(IntrinsicopNode &node, Operand &opnd0,
113                                           Operand &opnd1, Operand &opnd2) override;
114     RegOperand *SelectGetHeapConstantTable(IntrinsicopNode &node, Operand &opnd0,
115                                            Operand &opnd1, Operand &opnd2) override;
116     RegOperand *SelectTaggedObjectIsString(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1, Operand &opnd2,
117                                            Operand &opnd3, Operand &opnd4) override;
118     RegOperand *SelectIsCOWArray(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1, Operand &opnd2, Operand &opnd3,
119                                  Operand &opnd4, Operand &opnd5) override;
120     void SelectComment(CommentNode &comment) override;
121 
122     Operand *SelectDread(const BaseNode &parent, AddrofNode &expr) override;
123     RegOperand *SelectRegread(RegreadNode &expr) override;
124 
125     Operand *SelectIread(const BaseNode &parent, IreadNode &expr, int extraOffset = 0,
126                          PrimType finalBitFieldDestType = kPtyInvalid) override;
127     Operand *SelectIntConst(const MIRIntConst &intConst, const BaseNode &parent) override;
128     Operand *HandleFmovImm(PrimType stype, int64 val, MIRConst &mirConst, const BaseNode &parent);
129     Operand *SelectFloatConst(MIRFloatConst &floatConst, const BaseNode &parent) override;
130     Operand *SelectDoubleConst(MIRDoubleConst &doubleConst, const BaseNode &parent) override;
131 
132     void SelectAdd(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
133     Operand *SelectAdd(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
134     Operand *SelectShift(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
135     Operand *SelectSub(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
136     void SelectSub(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
137     Operand *SelectBand(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
138     void SelectBand(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
139     Operand *SelectBior(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
140     void SelectBior(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
141     Operand *SelectBxor(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
142     void SelectBxor(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
143 
144     void SelectBxorShift(Operand &resOpnd, Operand *o0, Operand *o1, Operand &o2, PrimType primType);
145     Operand *SelectMin(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
146     void SelectMin(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
147     Operand *SelectMax(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
148     void SelectMax(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
149     void SelectFMinFMax(Operand &resOpnd, Operand &o0, Operand &o1, bool is64Bits, bool isMin);
150     void SelectCmpOp(Operand &resOpnd, Operand &o0, Operand &o1, Opcode opCode, PrimType primType,
151                      const BaseNode &parent);
152 
153     Operand *SelectCmpOp(CompareNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
154 
155     void SelectAArch64Cmp(Operand &o, Operand &i, bool isIntType, uint32 dsize);
156     void SelectTargetFPCmpQuiet(Operand &o0, Operand &o1, uint32 dsize);
157     void SelectAArch64CSet(Operand &o, CondOperand &cond, bool is64Bits);
158     void SelectAArch64CSINV(Operand &res, Operand &o0, Operand &o1, CondOperand &cond, bool is64Bits);
159     void SelectAArch64CSINC(Operand &res, Operand &o0, Operand &o1, CondOperand &cond, bool is64Bits);
160     void SelectShift(Operand &resOpnd, Operand &o0, Operand &o1, ShiftDirection direct, PrimType primType);
161     Operand *SelectMpy(BinaryNode &node, Operand &o0, Operand &o1, const BaseNode &parent) override;
162     void SelectMpy(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType) override;
163     /* method description contains method information which is metadata for reflection. */
164     MemOperand *AdjustMemOperandIfOffsetOutOfRange(MemOperand *memOpnd, regno_t regNO, bool isDest, Insn &insn,
165                                                    AArch64reg regNum, bool &isOutOfRange);
166     void SelectAddAfterInsn(Operand &resOpnd, Operand &o0, Operand &o1, PrimType primType, bool isDest, Insn &insn);
167     bool IsImmediateOffsetOutOfRange(const MemOperand &memOpnd, uint32 bitLen);
168     bool IsOperandImmValid(MOperator mOp, Operand *o, uint32 opndIdx) const;
169     Operand *SelectRem(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent) override;
170     void SelectDiv(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType) override;
171     Operand *SelectDiv(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent) override;
172     Operand *SelectAbsSub(Insn &lastInsn, const UnaryNode &node, Operand &newOpnd0);
173     Operand *SelectAbs(UnaryNode &node, Operand &opnd0) override;
174     Operand *SelectBnot(UnaryNode &node, Operand &opnd0, const BaseNode &parent) override;
175     Operand *SelectExtractbits(ExtractbitsNode &node, Operand &opnd0, const BaseNode &parent) override;
176     Operand *SelectRegularBitFieldLoad(ExtractbitsNode &node, const BaseNode &parent) override;
177     Operand *SelectLnot(UnaryNode &node, Operand &opnd0, const BaseNode &parent) override;
178     Operand *SelectNeg(UnaryNode &node, Operand &opnd0, const BaseNode &parent) override;
179     void SelectNeg(Operand &dest, Operand &opnd0, PrimType primType);
180     void SelectMvn(Operand &dest, Operand &opnd0, PrimType primType);
181     Operand *SelectSqrt(UnaryNode &node, Operand &opnd0, const BaseNode &parent) override;
182     Operand *SelectCeil(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent) override;
183     Operand *SelectFloor(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent) override;
184     Operand *SelectRetype(TypeCvtNode &node, Operand &opnd0) override;
185     Operand *SelectCvt(const BaseNode &parent, TypeCvtNode &node, Operand &opnd0) override;
186     Operand *SelectTrunc(TypeCvtNode &node, Operand &opnd0, const BaseNode &parent) override;
187     void SelectAArch64Select(Operand &dest, Operand &opnd0, Operand &opnd1, CondOperand &cond, bool isIntType,
188                              uint32 is64bits);
189     void SelectRangeGoto(RangeGotoNode &rangeGotoNode, Operand &opnd0) override;
190     RegOperand &SelectCopy(Operand &src, PrimType stype, PrimType dtype) override;
191     void SelectCopy(Operand &dest, PrimType dtype, Operand &src, PrimType stype, BaseNode *baseNode = nullptr);
192     void SelectCopyImm(Operand &dest, PrimType dType, ImmOperand &src, PrimType sType);
193     void SelectCopyImm(Operand &dest, ImmOperand &src, PrimType dtype);
194     Operand &GetOrCreateRflag() override;
195     MemOperand *GetOrCreatSpillMem(regno_t vrNum, uint32 bitSize = k64BitSize) override;
196     const Operand *GetRflag() const override;
197     RegOperand &GetOrCreatevaryreg();
198     RegOperand &CreateRegisterOperandOfType(PrimType primType);
199     RegOperand &CreateRegisterOperandOfType(RegType regType, uint32 byteLen);
200     RegOperand &CreateRflagOperand();
201     RegOperand &GetOrCreateSpecialRegisterOperand(PregIdx sregIdx, PrimType primType);
202     void FreeSpillRegMem(regno_t vrNum);
203     RegOperand &GetOrCreatePhysicalRegisterOperand(AArch64reg regNO, uint32 size, RegType type, uint32 flag = 0);
204     RegOperand *CreateVirtualRegisterOperand(regno_t vRegNO, uint32 size, RegType kind, uint32 flg = 0) const;
205     RegOperand &CreateVirtualRegisterOperand(regno_t vregNO) override;
206     RegOperand &GetOrCreateVirtualRegisterOperand(regno_t vregNO) override;
207     const LabelOperand *GetLabelOperand(LabelIdx labIdx) const override;
208     LabelOperand &GetOrCreateLabelOperand(LabelIdx labIdx) override;
209     LabelOperand &GetOrCreateLabelOperand(BB &bb) override;
210 
211     bool DistanceCheck(const BB &bb, LabelIdx targLabIdx, uint32 targId, uint32 maxDistance) const;
212 
CreateImmOperand(PrimType ptyp,int64 val)213     ImmOperand &CreateImmOperand(PrimType ptyp, int64 val) override
214     {
215         return CreateImmOperand(val, GetPrimTypeBitSize(ptyp), IsSignedInteger(ptyp));
216     }
217 
218     /* create an integer immediate operand */
219     ImmOperand &CreateImmOperand(int64 val, uint32 size, bool isSigned, VaryType varyType = kNotVary,
220                                  bool isFmov = false) const
221     {
222         return *memPool->New<ImmOperand>(val, size, isSigned, varyType, isFmov);
223     }
224 
CreateImmOperand(Operand::OperandType type,int64 val,uint32 size,bool isSigned)225     ImmOperand &CreateImmOperand(Operand::OperandType type, int64 val, uint32 size, bool isSigned)
226     {
227         return *memPool->New<ImmOperand>(type, val, size, isSigned);
228     }
229 
CreateListOpnd(MapleAllocator & allocator)230     ListOperand *CreateListOpnd(MapleAllocator &allocator)
231     {
232         return memPool->New<ListOperand>(allocator);
233     }
234 
235     OfstOperand &GetOrCreateOfstOpnd(uint64 offset, uint32 size);
236 
CreateOfstOpnd(uint64 offset,uint32 size)237     OfstOperand &CreateOfstOpnd(uint64 offset, uint32 size) const
238     {
239         return *memPool->New<OfstOperand>(offset, size);
240     }
241 
CreateOfstOpnd(const MIRSymbol & mirSymbol,int32 relocs)242     OfstOperand &CreateOfstOpnd(const MIRSymbol &mirSymbol, int32 relocs) const
243     {
244         return *memPool->New<OfstOperand>(mirSymbol, 0, relocs);
245     }
246 
CreateOfstOpnd(const MIRSymbol & mirSymbol,int64 offset,int32 relocs)247     OfstOperand &CreateOfstOpnd(const MIRSymbol &mirSymbol, int64 offset, int32 relocs) const
248     {
249         return *memPool->New<OfstOperand>(mirSymbol, 0, offset, relocs);
250     }
251 
CreateStImmOperand(const MIRSymbol & mirSymbol,int64 offset,int32 relocs)252     StImmOperand &CreateStImmOperand(const MIRSymbol &mirSymbol, int64 offset, int32 relocs) const
253     {
254         return *memPool->New<StImmOperand>(mirSymbol, offset, relocs);
255     }
256 
GetOrCreateFramePointerRegOperand()257     RegOperand &GetOrCreateFramePointerRegOperand() override
258     {
259         return GetOrCreateStackBaseRegOperand();
260     }
261 
GetOrCreateStackBaseRegOperand()262     RegOperand &GetOrCreateStackBaseRegOperand() override
263     {
264         return GetOrCreatePhysicalRegisterOperand(RFP, GetPointerSize() * kBitsPerByte, kRegTyInt);
265     }
266 
GetOrCreateRegOpndFromPregIdx(PregIdx preg,PrimType type)267     RegOperand *GetOrCreateRegOpndFromPregIdx(PregIdx preg, PrimType type) override
268     {
269         DEBUG_ASSERT(preg > 0, "NIY, preg must be greater than 0.");
270         auto idx = static_cast<size_t>(preg);
271         if (pregIdx2Opnd[idx] == nullptr) {
272             pregIdx2Opnd[idx] = &GetOrCreateVirtualRegisterOperand(GetVirtualRegNOFromPseudoRegIdx(preg));
273         }
274         auto *regOpnd = pregIdx2Opnd[idx];
275         if (type == maple::PTY_ref) {
276             regOpnd->SetIsReference(true);
277             AddReferenceReg(regOpnd->GetRegisterNumber());
278         }
279         return regOpnd;
280     }
281 
282     MemOperand &GetOrCreateMemOpnd(const MIRSymbol &symbol, int64 offset, uint32 size, bool forLocalRef = false,
283                                    bool needLow12 = false, RegOperand *regOp = nullptr);
284 
285     MemOperand &HashMemOpnd(MemOperand &tMemOpnd);
286 
287     MemOperand &GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand *base,
288                                    RegOperand *index, ImmOperand *offset, const MIRSymbol *st);
289 
290     MemOperand &GetOrCreateMemOpnd(MemOperand::AArch64AddressingMode, uint32 size, RegOperand *base, RegOperand *index,
291                                    int32 shift, bool isSigned = false);
292 
293     MemOperand &GetOrCreateMemOpnd(MemOperand &oldMem);
294 
CreateMemOpnd(AArch64reg reg,int64 offset,uint32 size)295     MemOperand &CreateMemOpnd(AArch64reg reg, int64 offset, uint32 size)
296     {
297         RegOperand &baseOpnd = GetOrCreatePhysicalRegisterOperand(reg, GetPointerSize() * kBitsPerByte, kRegTyInt);
298         return CreateMemOpnd(baseOpnd, offset, size);
299     }
300 
301     MemOperand &CreateMemOpnd(RegOperand &baseOpnd, int64 offset, uint32 size);
302 
303     MemOperand &CreateMemOpnd(RegOperand &baseOpnd, int64 offset, uint32 size, const MIRSymbol &sym);
304 
305     MemOperand &CreateMemOpnd(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr, int64 offset = 0);
306 
307     MemOperand *CreateMemOpndOrNull(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr, int64 offset = 0);
308 
GetCondOperand(ConditionCode op)309     CondOperand &GetCondOperand(ConditionCode op) const
310     {
311         return ccOperands[op];
312     }
313 
314     BitShiftOperand *GetLogicalShiftLeftOperand(uint32 shiftAmount, bool is64bits) const;
315 
CreateBitShiftOperand(BitShiftOperand::ShiftOp op,uint32 amount,int32 bitLen)316     BitShiftOperand &CreateBitShiftOperand(BitShiftOperand::ShiftOp op, uint32 amount, int32 bitLen) const
317     {
318         return *memPool->New<BitShiftOperand>(op, amount, bitLen);
319     }
320 
CreateExtendShiftOperand(ExtendShiftOperand::ExtendOp op,uint32 amount,int32 bitLen)321     ExtendShiftOperand &CreateExtendShiftOperand(ExtendShiftOperand::ExtendOp op, uint32 amount, int32 bitLen) const
322     {
323         return *memPool->New<ExtendShiftOperand>(op, amount, bitLen);
324     }
325 
326     Operand &GetOrCreateFuncNameOpnd(const MIRSymbol &symbol) const;
327     RegOperand *GetBaseReg(const SymbolAlloc &symAlloc) override;
328     int32 GetBaseOffset(const SymbolAlloc &symAlloc) override;
329 
CreateCommentOperand(const std::string & s)330     Operand &CreateCommentOperand(const std::string &s) const
331     {
332         return *memPool->New<CommentOperand>(s, *memPool);
333     }
334 
CreateCommentOperand(const MapleString & s)335     Operand &CreateCommentOperand(const MapleString &s) const
336     {
337         return *memPool->New<CommentOperand>(s.c_str(), *memPool);
338     }
339 
AddtoCalleeSaved(regno_t reg)340     void AddtoCalleeSaved(regno_t reg) override
341     {
342         if (!UseFP() && reg == R29) {
343             reg = RFP;
344         }
345         if (find(calleeSavedRegs.begin(), calleeSavedRegs.end(), reg) != calleeSavedRegs.end()) {
346             return;
347         }
348         calleeSavedRegs.emplace_back(static_cast<AArch64reg>(reg));
349         DEBUG_ASSERT((AArch64isa::IsGPRegister(static_cast<AArch64reg>(reg)) ||
350                       AArch64isa::IsFPSIMDRegister(static_cast<AArch64reg>(reg))),
351                      "Int or FP registers are expected");
352         if (AArch64isa::IsGPRegister(static_cast<AArch64reg>(reg))) {
353             ++numIntregToCalleeSave;
354         } else {
355             ++numFpregToCalleeSave;
356         }
357     }
358 
SizeOfCalleeSaved()359     uint32 SizeOfCalleeSaved() const
360     {
361         /* npairs = num / 2 + num % 2 */
362         uint32 nPairs = (numIntregToCalleeSave >> 1) + (numIntregToCalleeSave & 0x1);
363         nPairs += (numFpregToCalleeSave >> 1) + (numFpregToCalleeSave & 0x1);
364         return (nPairs * (kAarch64IntregBytelen << 1));
365     }
366 
NoteFPLRAddedToCalleeSavedList()367     void NoteFPLRAddedToCalleeSavedList()
368     {
369         fplrAddedToCalleeSaved = true;
370     }
371 
IsFPLRAddedToCalleeSavedList()372     bool IsFPLRAddedToCalleeSavedList() const
373     {
374         return fplrAddedToCalleeSaved;
375     }
376 
IsIntrnCallForC()377     bool IsIntrnCallForC() const
378     {
379         return isIntrnCallForC;
380     }
381 
UsedStpSubPairForCallFrameAllocation()382     bool UsedStpSubPairForCallFrameAllocation() const
383     {
384         return usedStpSubPairToAllocateCallFrame;
385     }
SetUsedStpSubPairForCallFrameAllocation(bool val)386     void SetUsedStpSubPairForCallFrameAllocation(bool val)
387     {
388         usedStpSubPairToAllocateCallFrame = val;
389     }
390 
GetCalleeSavedRegs()391     const MapleVector<AArch64reg> &GetCalleeSavedRegs() const
392     {
393         return calleeSavedRegs;
394     }
395 
396     MemOperand &CreateStkTopOpnd(uint32 offset, uint32 size);
397     MemOperand *CreateStackMemOpnd(regno_t preg, int32 offset, uint32 size);
398     MemOperand *CreateMemOperand(uint32 size, RegOperand &base, ImmOperand &ofstOp, bool isVolatile,
399                                  MemOperand::AArch64AddressingMode mode = MemOperand::kAddrModeBOi) const;
400     MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base,
401                                  RegOperand *index, ImmOperand *offset, const MIRSymbol *symbol) const;
402     MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base,
403                                  RegOperand &index, ImmOperand *offset, const MIRSymbol &symbol, bool noExtend);
404     MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 dSize, RegOperand &base,
405                                  RegOperand &indexOpnd, uint32 shift, bool isSigned = false) const;
406     MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 dSize, const MIRSymbol &sym);
407 
408     /* if offset < 0, allocation; otherwise, deallocation */
409     MemOperand &CreateCallFrameOperand(int32 offset, uint32 size);
410 
411     void AppendCall(const MIRSymbol &func);
412     Insn &AppendCall(const MIRSymbol &func, ListOperand &srcOpnds);
413 
414     static constexpr uint32 kDwarfFpRegBegin = 64;
415     static constexpr int32 kBitLenOfShift64Bits =
416         6; /* for 64 bits register, shift amount is 0~63, use 6 bits to store */
417     static constexpr int32 kBitLenOfShift32Bits =
418         5; /* for 32 bits register, shift amount is 0~31, use 5 bits to store */
419     static constexpr int32 kHighestBitOf64Bits = 63; /* 63 is highest bit of a 64 bits number */
420     static constexpr int32 kHighestBitOf32Bits = 31; /* 31 is highest bit of a 32 bits number */
421     static constexpr int32 k16ValidBit = 16;
422 
423     /* CFI directives related stuffs */
CreateCfiRegOperand(uint32 reg,uint32 size)424     Operand &CreateCfiRegOperand(uint32 reg, uint32 size) override
425     {
426         /*
427          * DWARF for ARM Architecture (ARM IHI 0040B) 3.1 Table 1
428          * Having kRinvalid=0 (see arm32_isa.h) means
429          * each register gets assigned an id number one greater than
430          * its physical number
431          */
432         if (reg < V0) {
433             return *memPool->New<cfi::RegOperand>((reg - R0), size);
434         } else {
435             return *memPool->New<cfi::RegOperand>((reg - V0) + kDwarfFpRegBegin, size);
436         }
437     }
438 
439     MOperator PickStInsn(uint32 bitSize, PrimType primType) const;
440     MOperator PickLdInsn(uint32 bitSize, PrimType primType) const;
441     MOperator PickExtInsn(PrimType dtype, PrimType stype) const;
442 
443     bool CheckIfSplitOffsetWithAdd(const MemOperand &memOpnd, uint32 bitLen) const;
444     RegOperand *GetBaseRegForSplit(uint32 baseRegNum);
445 
446     MemOperand &SplitOffsetWithAddInstruction(const MemOperand &memOpnd, uint32 bitLen,
447                                               uint32 baseRegNum = AArch64reg::kRinvalid, bool isDest = false,
448                                               Insn *insn = nullptr, bool forPair = false);
449     ImmOperand &SplitAndGetRemained(const MemOperand &memOpnd, uint32 bitLen, RegOperand *resOpnd, int64 ofstVal,
450                                     bool isDest = false, Insn *insn = nullptr, bool forPair = false);
451     MemOperand &CreateReplacementMemOperand(uint32 bitLen, RegOperand &baseReg, int64 offset);
452 
453     MemOperand &LoadStructCopyBase(const MIRSymbol &symbol, int64 offset, int datasize);
454 
GetSplitBaseOffset()455     int32 GetSplitBaseOffset() const
456     {
457         return splitStpldpBaseOffset;
458     }
SetSplitBaseOffset(int32 val)459     void SetSplitBaseOffset(int32 val)
460     {
461         splitStpldpBaseOffset = val;
462     }
463 
CreateCommentInsn(const std::string & comment)464     Insn &CreateCommentInsn(const std::string &comment)
465     {
466         Insn &insn = GetInsnBuilder()->BuildInsn(abstract::MOP_comment, InsnDesc::GetAbstractId(abstract::MOP_comment));
467         insn.AddOperand(CreateCommentOperand(comment));
468         return insn;
469     }
470 
CreateCommentInsn(const MapleString & comment)471     Insn &CreateCommentInsn(const MapleString &comment)
472     {
473         Insn &insn = GetInsnBuilder()->BuildInsn(abstract::MOP_comment, InsnDesc::GetAbstractId(abstract::MOP_comment));
474         insn.AddOperand(CreateCommentOperand(comment));
475         return insn;
476     }
477 
CreateCfiRestoreInsn(uint32 reg,uint32 size)478     Insn &CreateCfiRestoreInsn(uint32 reg, uint32 size)
479     {
480         return GetInsnBuilder()->BuildCfiInsn(cfi::OP_CFI_restore).AddOpndChain(CreateCfiRegOperand(reg, size));
481     }
482 
CreateCfiOffsetInsn(uint32 reg,int64 val,uint32 size)483     Insn &CreateCfiOffsetInsn(uint32 reg, int64 val, uint32 size)
484     {
485         return GetInsnBuilder()
486             ->BuildCfiInsn(cfi::OP_CFI_offset)
487             .AddOpndChain(CreateCfiRegOperand(reg, size))
488             .AddOpndChain(CreateCfiImmOperand(val, size));
489     }
CreateCfiDefCfaInsn(uint32 reg,int64 val,uint32 size)490     Insn &CreateCfiDefCfaInsn(uint32 reg, int64 val, uint32 size)
491     {
492         return GetInsnBuilder()
493             ->BuildCfiInsn(cfi::OP_CFI_def_cfa)
494             .AddOpndChain(CreateCfiRegOperand(reg, size))
495             .AddOpndChain(CreateCfiImmOperand(val, size));
496     }
497 
NewInsnModifier()498     InsnVisitor *NewInsnModifier() override
499     {
500         return memPool->New<AArch64InsnVisitor>(*this);
501     }
502 
503     RegType GetRegisterType(regno_t reg) const override;
504 
MaxCondBranchDistance()505     uint32 MaxCondBranchDistance() override
506     {
507         return AArch64Abi::kMaxInstrForCondBr;
508     }
509 
510     void InsertJumpPad(Insn *insn) override;
511 
GetProEpilogSavedRegs()512     MapleVector<AArch64reg> &GetProEpilogSavedRegs()
513     {
514         return proEpilogSavedRegs;
515     }
516 
GetDefaultAlignPow()517     uint32 GetDefaultAlignPow() const
518     {
519         return alignPow;
520     }
521 
522     RegOperand &GetZeroOpnd(uint32 size) override;
523 
GetStoreFP()524     bool GetStoreFP() const
525     {
526         return storeFP;
527     }
SetStoreFP(bool val)528     void SetStoreFP(bool val)
529     {
530         storeFP = val;
531     }
532 
GetLabelInInsn(Insn & insn)533     LabelIdx GetLabelInInsn(Insn &insn) override
534     {
535         return static_cast<LabelOperand &>(insn.GetOperand(AArch64isa::GetJumpTargetIdx(insn))).GetLabelIndex();
536     }
537 
538 private:
539     enum RelationOperator : uint8 { kAND, kIOR, kEOR };
540 
541     enum RelationOperatorOpndPattern : uint8 { kRegReg, kRegImm };
542 
543     enum RoundType : uint8 { kCeil, kFloor, kRound, kTrunc };
544 
545     static constexpr int32 kMaxMovkLslEntries = 8;
546     using MovkLslOperandArray = std::array<BitShiftOperand, kMaxMovkLslEntries>;
547 
548     MapleVector<AArch64reg> calleeSavedRegs;
549     MapleVector<AArch64reg> proEpilogSavedRegs;
550 
551     MapleUnorderedMap<phyRegIdx, RegOperand *> phyRegOperandTable; /* machine register operand table */
552     MapleUnorderedMap<LabelIdx, LabelOperand *> hashLabelOpndTable;
553     MapleUnorderedMap<OfstRegIdx, OfstOperand *> hashOfstOpndTable;
554     MapleUnorderedMap<MemOperand, MemOperand *> hashMemOpndTable;
555     /*
556      * Local variables, formal parameters that are passed via registers
557      * need offset adjustment after callee-saved registers are known.
558      */
559     MapleUnorderedMap<StIdx, MemOperand *> memOpndsRequiringOffsetAdjustment;
560     MapleUnorderedMap<StIdx, MemOperand *> memOpndsForStkPassedArguments;
561     MapleUnorderedMap<AArch64SymbolAlloc *, ImmOperand *> immOpndsRequiringOffsetAdjustment;
562     MapleUnorderedMap<AArch64SymbolAlloc *, ImmOperand *> immOpndsRequiringOffsetAdjustmentForRefloc;
563     MapleUnorderedMap<CallConvKind, CCImpl *> hashCCTable;
564 
565     Operand *rcc = nullptr;
566     RegOperand *vary = nullptr;
567     RegOperand *fsp = nullptr; /* used to point the address of local variables and formal parameters */
568 
569     static CondOperand ccOperands[kCcLast];
570     static MovkLslOperandArray movkLslOperands;
571     uint32 numIntregToCalleeSave = 0;
572     uint32 numFpregToCalleeSave = 0;
573     bool fplrAddedToCalleeSaved = false;
574     bool isIntrnCallForC = false;
575     bool usedStpSubPairToAllocateCallFrame = false;
576     int32 splitStpldpBaseOffset = 0;
577     uint32 alignPow = 5; /* function align pow defaults to 5   i.e. 2^5*/
578     bool storeFP = false;
579 
580     MOperator PickJmpInsn(Opcode brOp, Opcode cmpOp, bool isFloat, bool isSigned) const;
581 
GetOperandTy(bool isIntty,uint32 dsize,bool isSigned)582     PrimType GetOperandTy(bool isIntty, uint32 dsize, bool isSigned) const
583     {
584         DEBUG_ASSERT(!isSigned || isIntty, "");
585         return (isIntty ? ((dsize == k64BitSize) ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32))
586                         : ((dsize == k64BitSize) ? PTY_f64 : PTY_f32));
587     }
588 
589     RegOperand &LoadIntoRegister(Operand &o, bool isIntty, uint32 dsize, bool asSigned = false)
590     {
591         PrimType pTy;
592         if (o.GetKind() == Operand::kOpdRegister && static_cast<RegOperand &>(o).GetRegisterType() == kRegTyFloat) {
593             // f128 is a vector placeholder, no use for now
594             pTy = dsize == k32BitSize ? PTY_f32 : PTY_f64;
595         } else {
596             pTy = GetOperandTy(isIntty, dsize, asSigned);
597         }
598         return LoadIntoRegister(o, pTy);
599     }
600 
LoadIntoRegister(Operand & o,PrimType oty)601     RegOperand &LoadIntoRegister(Operand &o, PrimType oty)
602     {
603         return (o.IsRegister() ? static_cast<RegOperand &>(o) : SelectCopy(o, oty, oty));
604     }
605 
LoadIntoRegister(Operand & o,PrimType dty,PrimType sty)606     RegOperand &LoadIntoRegister(Operand &o, PrimType dty, PrimType sty)
607     {
608         return (o.IsRegister() ? static_cast<RegOperand &>(o) : SelectCopy(o, sty, dty));
609     }
610 
611     struct ParamDesc {
612         ParamDesc(MIRType *type, BaseNode *expr, uint32 ofst = 0, bool copyed = false)
mirTypeParamDesc613             : mirType(type), argExpr(expr), offset(ofst), preCopyed(copyed)
614         {
615         }
616         MIRType *mirType = nullptr;
617         BaseNode *argExpr = nullptr;  // expr node
618         uint32 offset = 0;            // agg offset, for preCopyed struct, RSP-based offset
619         bool preCopyed = false;       // for large struct, pre copyed to strack
620         bool isSpecialArg = false;    // such as : tls
621     };
622 
623     std::pair<MIRFunction *, MIRFuncType *> GetCalleeFunction(StmtNode &naryNode) const;
624     bool SelectParmListPreprocess(StmtNode &naryNode, size_t start, std::vector<ParamDesc> &argsDesc,
625                                   const MIRFunction *callee = nullptr);
626     void SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative = false);
627     void SelectParmListNotC(StmtNode &naryNode, ListOperand &srcOpnds);
628     void DoOptForStackStrInsns(std::vector<Insn *> &insnForStackArgs, std::vector<Insn *> &optInsns);
629     bool CheckStrPairOpt(Insn *insn1, Insn *insn2);
630     void SelectRem(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType, bool isSigned, bool is64Bits);
631     void SelectCvtInt2Int(const BaseNode *parent, Operand *&resOpnd, Operand *opnd0, PrimType fromType,
632                           PrimType toType);
633     void SelectCvtFloat2Float(Operand &resOpnd, Operand &opnd0, PrimType fromType, PrimType toType);
634     void SelectCvtFloat2Int(Operand &resOpnd, Operand &opnd0, PrimType itype, PrimType ftype);
635     void SelectCvtInt2Float(Operand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType);
636     Operand *SelectRelationOperator(RelationOperator operatorCode, const BinaryNode &node, Operand &opnd0,
637                                     Operand &opnd1, const BaseNode &parent);
638     void SelectRelationOperator(RelationOperator operatorCode, Operand &resOpnd, Operand &opnd0, Operand &opnd1,
639                                 PrimType primType);
640     MOperator SelectRelationMop(RelationOperator operatorType, RelationOperatorOpndPattern opndPattern, bool is64Bits,
641                                 bool IsBitmaskImmediate, bool isBitNumLessThan16) const;
642     Operand *SelectMinOrMax(bool isMin, const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent);
643     void SelectMinOrMax(bool isMin, Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType);
644     Operand *SelectRoundOperator(RoundType roundType, const TypeCvtNode &node, Operand &opnd0, const BaseNode &parent);
645     void SelectCopyMemOpnd(Operand &dest, PrimType dtype, uint32 dsize, Operand &src, PrimType stype);
646     void SelectCopyRegOpnd(Operand &dest, PrimType dtype, Operand::OperandType opndType, uint32 dsize, Operand &src,
647                            PrimType stype);
648     bool GenerateCompareWithZeroInstruction(Opcode jmpOp, Opcode cmpOp, bool is64Bits, PrimType primType,
649                                             LabelOperand &targetOpnd, Operand &opnd0);
650     void SelectOverFlowCall(const IntrinsiccallNode &intrnNode);
651     RegOperand &LoadOpndIntoPhysicalRegister(const IntrinsiccallNode &intrnNode, uint32 index);
652     void SelectPureCall(const IntrinsiccallNode &intrnNode);
653 
654     /* Helper functions for translating complex Maple IR instructions/inrinsics */
655     void SelectDassign(StIdx stIdx, FieldID fieldId, PrimType rhsPType, Operand &opnd0);
656 
657     MemOperand *GetPseudoRegisterSpillMemoryOperand(PregIdx i) override;
658 
659     bool IsStoreMop(MOperator mOp) const;
660     bool IsImmediateValueInRange(MOperator mOp, int64 immVal, bool is64Bits, bool isIntactIndexed, bool isPostIndexed,
661                                  bool isPreIndexed) const;
662 
663     MemOperand *CheckAndCreateExtendMemOpnd(PrimType ptype, const BaseNode &addrExpr, int64 offset);
664     MemOperand &CreateNonExtendMemOpnd(PrimType ptype, const BaseNode &parent, BaseNode &addrExpr, int64 offset);
665     void SelectParmListWrapper(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative);
666 };
667 } /* namespace maplebe */
668 
669 #endif /* MAPLEBE_INCLUDE_CG_AARCH64_AARCH64_CGFUNC_H */
670