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