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