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