diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/be/becommon.h b/ecmascript/compiler/codegen/maple/maple_be/include/be/becommon.h index 8e5fb7ff282c7b7a024c104d5435ee73f2758833..181413a070b25c2bb6f20b609fdb489a7a8e19f0 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/be/becommon.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/be/becommon.h @@ -100,6 +100,8 @@ public: std::pair GetFieldOffset(MIRStructType &structType, FieldID fieldID); + FieldInfo GetJClassFieldOffset(MIRStructType &classType, FieldID fieldID) const; + bool IsRefField(MIRStructType &structType, FieldID fieldID) const; /* some class may has incomplete type definition. provide an interface to check them. */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/be/lower.h b/ecmascript/compiler/codegen/maple/maple_be/include/be/lower.h index 9cb3831bcfba3fab32d4e9b8993cc46627751204..2dd6aa00cbffb6f60fb0077415a1008fa3be5235 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/be/lower.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/be/lower.h @@ -178,7 +178,11 @@ public: * To be able to handle them in a unified manner, we lower intrinsiccall to Intrinsicsicop. */ BlockNode *LowerIntrinsiccallToIntrinsicop(StmtNode &stmt); - bool LowerStructReturn(BlockNode &blk, StmtNode *stmt, StmtNode *&nextStmt, bool &lvar, BlockNode *oldblk); + bool LowerStructReturnInRegs(BlockNode &newBlk, StmtNode &stmt, const MIRSymbol &retSym); + void LowerStructReturnInGpRegs(BlockNode &newBlk, const StmtNode &stmt, const MIRSymbol &symbol); + void LowerStructReturnInFpRegs(BlockNode &newBlk, const StmtNode &stmt, const MIRSymbol &symbol, PrimType primType, + size_t elemNum); + bool LowerStructReturn(BlockNode &newBlk, StmtNode &stmt, bool &lvar); BlockNode *LowerMemop(StmtNode &); BaseNode *LowerRem(BaseNode &rem, BlockNode &block); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_abi.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_abi.h index 8fb32951d3a5ba36e2cdf7a946217cc3e0c366f7..4e6979cf1ff4236224571c0a7875188122450ec1 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_abi.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_abi.h @@ -28,14 +28,14 @@ constexpr int32 kNumIntParmRegs = 8; constexpr int32 kNumFloatParmRegs = 8; constexpr int32 kYieldPointReservedReg = 19; constexpr uint32 kNormalUseOperandNum = 3; -constexpr uint32 kMaxInstrForTbnz = 8000; // approximately less than (2^13); -constexpr uint32 kMaxInstrForCondBr = 260000; // approximately less than (2^18); -constexpr uint32 kMaxInstrForLdr = 260000; // approximately less than (2^18); - -constexpr AArch64reg intReturnRegs[kNumIntParmRegs] = {R0, R1, R2, R3, R4, R5, R6, R7}; -constexpr AArch64reg floatReturnRegs[kNumFloatParmRegs] = {V0, V1, V2, V3, V4, V5, V6, V7}; -constexpr AArch64reg intParmRegs[kNumIntParmRegs] = {R0, R1, R2, R3, R4, R5, R6, R7}; -constexpr AArch64reg floatParmRegs[kNumFloatParmRegs] = {V0, V1, V2, V3, V4, V5, V6, V7}; +constexpr uint32 kMaxInstrForTbnz = 8000; // approximately less than (2^13); +constexpr uint32 kMaxInstrForCondBr = 260000; // approximately less than (2^18); +constexpr uint32 kMaxInstrForLdr = 260000; // approximately less than (2^18); + +extern std::vector intReturnRegs; +extern std::vector floatReturnRegs; +extern std::vector intParmRegs; +extern std::vector floatParmRegs; /* * Refer to ARM IHI 0055C_beta: Procedure Call Standard for diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_args.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_args.h index 89bdbc8335e28c735967f79aff8956547bf60c60..abc92fd2e272afbc63684b8914d16489b124f0f4 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_args.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_args.h @@ -22,44 +22,31 @@ namespace maplebe { using namespace maple; -struct AArch64ArgInfo { - AArch64reg reg; - MIRType *mirTy; - uint32 symSize; - uint32 stkSize; - RegType regType; - MIRSymbol *sym; - const AArch64SymbolAlloc *symLoc; - uint8 memPairSecondRegSize; /* struct arg requiring two regs, size of 2nd reg */ - bool doMemPairOpt; - bool createTwoStores; - bool isTwoRegParm; -}; - class AArch64MoveRegArgs : public MoveRegArgs { public: - explicit AArch64MoveRegArgs(CGFunc &func) : MoveRegArgs(func) {} - ~AArch64MoveRegArgs() override = default; + explicit AArch64MoveRegArgs(CGFunc &func) : MoveRegArgs(func) + { + aarFunc = static_cast(&func); + } + ~AArch64MoveRegArgs() override + { + aarFunc = nullptr; + } void Run() override; private: - RegOperand *baseReg = nullptr; - const MemSegment *lastSegment = nullptr; - void CollectRegisterArgs(std::map &argsList, std::vector &indexList, - std::map &pairReg, std::vector &numFpRegs, - std::vector &fpSize) const; - AArch64ArgInfo GetArgInfo(std::map &argsList, std::vector &numFpRegs, - std::vector &fpSize, uint32 argIndex) const; - bool IsInSameSegment(const AArch64ArgInfo &firstArgInfo, const AArch64ArgInfo &secondArgInfo) const; - void GenOneInsn(const AArch64ArgInfo &argInfo, RegOperand &baseOpnd, uint32 stBitSize, AArch64reg dest, - int32 offset) const; - void GenerateStpInsn(const AArch64ArgInfo &firstArgInfo, const AArch64ArgInfo &secondArgInfo); - void GenerateStrInsn(const AArch64ArgInfo &argInfo, AArch64reg reg2, uint32 numFpRegs, uint32 fpSize); - void MoveRegisterArgs(); + // gen param to stack + // call foo(var $a) -> str X0, [memOpnd] + void MoveRegisterArgs() const; + // gen param to preg + // call foo(%1) -> mov V201, X0 void MoveVRegisterArgs(); void MoveLocalRefVarToRefLocals(MIRSymbol &mirSym) const; void LoadStackArgsToVReg(MIRSymbol &mirSym) const; void MoveArgsToVReg(const CCLocInfo &ploc, MIRSymbol &mirSym) const; + Insn &CreateMoveArgsToVRegInsn(MOperator mOp, RegOperand &destOpnd, RegOperand &srcOpnd, PrimType primType) const; + + AArch64CGFunc *aarFunc = nullptr; }; } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_call_conv.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_call_conv.h index 7fa617c173dd84a145c984fa17775cc203f42099..5656133ab35d69e19690ab1f7cda6aacb5bee044 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_call_conv.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_call_conv.h @@ -26,7 +26,8 @@ namespace maplebe { using namespace maple; /* - * We use the names used in ARM IHI 0055C_beta. $ 5.4.2. + * We use the names used in Procedure Call Standard for the Arm 64-bit + * Architecture (AArch64) 2022Q3. $6.8.2 * nextGeneralRegNO (= _int_parm_num) : Next General-purpose Register number * nextFloatRegNO (= _float_parm_num): Next SIMD and Floating-point Register Number * nextStackArgAdress (= _last_memOffset): Next Stacked Argument Address @@ -40,15 +41,13 @@ public: ~AArch64CallConvImpl() = default; /* Return size of aggregate structure copy on stack. */ - int32 LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, MIRFunction *func = nullptr) override; + uint64 LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, + MIRFuncType *tFunc = nullptr) override; - int32 LocateRetVal(MIRType &retType, CCLocInfo &ploc) override; + void LocateRetVal(const MIRType &retType, CCLocInfo &ploc) override; /* for lmbc */ - uint32 FloatParamRegRequired(MIRStructType &structType, uint32 &fpSize); - - /* return value related */ - void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc) override; + uint32 FloatParamRegRequired(const MIRStructType &structType, uint32 &fpSize); void SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc) const override; @@ -56,12 +55,11 @@ public: { pLoc.regCount = 1; pLoc.reg0 = R8; - pLoc.primTypeOfReg0 = PTY_u64; + pLoc.primTypeOfReg0 = GetExactPtrPrimType(); } void Init() override { - paramNum = 0; nextGeneralRegNO = 0; nextFloatRegNO = 0; nextStackArgAdress = 0; @@ -69,9 +67,8 @@ public: private: BECommon &beCommon; - uint64 paramNum = 0; /* number of all types of parameters processed so far */ - int32 nextGeneralRegNO = 0; /* number of integer parameters processed so far */ - uint32 nextFloatRegNO = 0; /* number of float parameters processed so far */ + uint32 nextGeneralRegNO = 0; /* number of integer parameters processed so far */ + uint32 nextFloatRegNO = 0; /* number of float parameters processed so far */ AArch64reg AllocateGPRegister() { @@ -80,15 +77,7 @@ private: : kRinvalid; } - void AllocateTwoGPRegisters(CCLocInfo &pLoc) - { - if ((nextGeneralRegNO + 1) < AArch64Abi::kNumIntParmRegs) { - pLoc.reg0 = AArch64Abi::intParmRegs[nextGeneralRegNO++]; - pLoc.reg1 = AArch64Abi::intParmRegs[nextGeneralRegNO++]; - } else { - pLoc.reg0 = kRinvalid; - } - } + void AllocateGPRegister(const MIRType &mirType, CCLocInfo &pLoc, uint64 size, uint64 align); AArch64reg AllocateSIMDFPRegister() { @@ -96,42 +85,7 @@ private: : kRinvalid; } - void AllocateNSIMDFPRegisters(CCLocInfo &ploc, uint32 num) - { - if ((nextFloatRegNO + num - 1) < AArch64Abi::kNumFloatParmRegs) { - switch (num) { - case kOneRegister: - ploc.reg0 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - break; - case kTwoRegister: - ploc.reg0 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg1 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - break; - case kThreeRegister: - ploc.reg0 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg1 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg2 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - break; - case kFourRegister: - ploc.reg0 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg1 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg2 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - ploc.reg3 = AArch64Abi::floatParmRegs[nextFloatRegNO++]; - break; - default: - CHECK_FATAL(0, "AllocateNSIMDFPRegisters: unsupported"); - } - } else { - ploc.reg0 = kRinvalid; - } - } - - void RoundNGRNUpToNextEven() - { - nextGeneralRegNO = static_cast((nextGeneralRegNO + 1) & ~static_cast(1)); - } - - int32 ProcessPtyAggWhenLocateNextParm(MIRType &mirType, CCLocInfo &pLoc, uint64 &typeSize, int32 typeAlign); + uint64 AllocateRegisterForAgg(const MIRType &mirType, CCLocInfo &pLoc, uint64 size, uint64 &align); }; class AArch64WebKitJSCC : public CCImpl { @@ -141,12 +95,13 @@ public: ~AArch64WebKitJSCC() = default; /* Return size of aggregate structure copy on stack. */ - int32 LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, MIRFunction *func = nullptr) override; + uint64 LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, + MIRFuncType *func = nullptr) override; - int32 LocateRetVal(MIRType &retType, CCLocInfo &ploc) override; + void LocateRetVal(const MIRType &retType, CCLocInfo &ploc) override; /* return value related */ - void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc) override; + void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc); // invalid interface void SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc) const override; @@ -171,9 +126,9 @@ private: static constexpr AArch64reg intParmRegs[kNumIntParmRegs] = {R0}; static constexpr AArch64reg floatParmRegs[kNumFloatParmRegs] = {}; - int32 ClassificationArg(const BECommon &be, MIRType &mirType, std::vector &classes) const; + int32 ClassificationArg(const BECommon &be, const MIRType &mirType, std::vector &classes) const; - int32 ClassificationRet(const BECommon &be, MIRType &mirType, std::vector &classes) const; + int32 ClassificationRet(const BECommon &be, const MIRType &mirType, std::vector &classes) const; AArch64reg AllocateGPParmRegister() { @@ -206,12 +161,13 @@ public: ~GHCCC() = default; /* Return size of aggregate structure copy on stack. */ - int32 LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, MIRFunction *func = nullptr) override; + uint64 LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, + MIRFuncType *func = nullptr) override; - int32 LocateRetVal(MIRType &retType, CCLocInfo &ploc) override; + void LocateRetVal(const MIRType &retType, CCLocInfo &ploc) override; /* return value related */ - void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc) override; + void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc); // invalid interface void SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc) const override; @@ -240,7 +196,7 @@ private: static constexpr AArch64reg floatParmRegsF64[kNumFloatParmRegsF64] = {V12, V13, V14, V15}; static constexpr AArch64reg floatParmRegsF128[kNumFloatParmRegsF128] = {V4, V5}; - int32 ClassificationArg(const BECommon &be, MIRType &mirType, std::vector &classes) const; + int32 ClassificationArg(const BECommon &be, const MIRType &mirType, std::vector &classes) const; AArch64reg AllocateGPParmRegister() { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h index 81e6d7a8da396b0ecee80a4e481bd04d86f031ed..face872a4d13de74e879874b99d8ff39532a3832 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h @@ -130,13 +130,16 @@ public: bool GenRetCleanup(const IntrinsiccallNode *cleanupNode, bool forEA = false); void HandleRetCleanup(NaryStmtNode &retNode) override; void MergeReturn() override; - RegOperand *ExtractNewMemBase(const MemOperand &memOpnd); + RegOperand *ExtractMemBaseAddr(const MemOperand &memOpnd); void SelectDassign(DassignNode &stmt, Operand &opnd0) override; void SelectDassignoff(DassignoffNode &stmt, Operand &opnd0) override; void SelectRegassign(RegassignNode &stmt, Operand &opnd0) override; void SelectAbort() override; void SelectAssertNull(UnaryStmtNode &stmt) override; void SelectAsm(AsmNode &stmt) override; + MemOperand *GenFormalMemOpndWithSymbol(const MIRSymbol &sym, int64 offset); + MemOperand *SelectRhsMemOpnd(BaseNode &rhsStmt, bool &isRefField); + MemOperand *SelectRhsMemOpnd(BaseNode &rhsStmt); MemOperand *GenLargeAggFormalMemOpnd(const MIRSymbol &sym, uint32 alignUsed, int64 offset, bool needLow12 = false); MemOperand *FixLargeMemOpnd(MemOperand &memOpnd, uint32 align); MemOperand *FixLargeMemOpnd(MOperator mOp, MemOperand &memOpnd, uint32 dSize, uint32 opndIdx); @@ -154,6 +157,11 @@ public: void SelectReturnSendOfStructInRegs(BaseNode *x) override; void SelectReturn(Operand *opnd0) override; void SelectIgoto(Operand *opnd0) override; + bool DoCallerEnsureValidParm(RegOperand &destOpnd, RegOperand &srcOpnd, PrimType formalPType); + void SelectParmListSmallStruct(const MIRType &mirType, const CCLocInfo &ploc, Operand &addr, ListOperand &srcOpnds, + bool isSpecialArg, std::vector ®MapForTmpBB); + void SelectParmListPassByStack(const MIRType &mirType, Operand &opnd, uint32 memOffset, bool preCopyed, + std::vector &insnForStackArgs); void SelectCondGoto(CondGotoNode &stmt, Operand &opnd0, Operand &opnd1) override; void SelectCondGoto(LabelOperand &targetOpnd, Opcode jmpOp, Opcode cmpOp, Operand &opnd0, Operand &opnd1, PrimType primType, bool signedCond); @@ -311,7 +319,7 @@ public: Operand &GetOrCreateRflag() override; MemOperand *GetOrCreatSpillMem(regno_t vrNum, uint32 bitSize = k64BitSize) override; const Operand *GetRflag() const override; - Operand &GetOrCreatevaryreg(); + RegOperand &GetOrCreatevaryreg(); RegOperand &CreateRegisterOperandOfType(PrimType primType); RegOperand &CreateRegisterOperandOfType(RegType regType, uint32 byteLen); RegOperand &CreateRflagOperand(); @@ -447,7 +455,16 @@ public: return GetOrCreatePhysicalRegisterOperand(reg, GetPointerSize() * kBitsPerByte, kRegTyInt); } + struct SplittedInt128 { + Operand &low; + Operand &high; + }; + + void SetMemReferenceOfInsn(Insn &insn, BaseNode *baseNode); + struct SplittedInt128 SplitInt128(Operand &opnd); RegOperand &GenStructParamIndex(RegOperand &base, const BaseNode &indexExpr, int shift, PrimType baseType); + void SelectParmListForInt128(Operand &opnd, ListOperand &srcOpnds, const CCLocInfo &ploc, bool isSpecialArg, + std::vector ®MapForTmpBB); void SelectAddrofAfterRa(Operand &result, StImmOperand &stImm, std::vector &rematInsns); MemOperand &GetOrCreateMemOpndAfterRa(const MIRSymbol &symbol, int32 offset, uint32 size, bool needLow12, RegOperand *regOp, std::vector &rematInsns); @@ -502,7 +519,6 @@ public: Operand &GetOrCreateFuncNameOpnd(const MIRSymbol &symbol) const; void GenerateYieldpoint(BB &bb) override; - Operand &ProcessReturnReg(PrimType primType, int32 sReg) override; void GenerateCleanupCode(BB &bb) override; bool NeedCleanup() override; void GenerateCleanupCodeForExtEpilog(BB &bb) override; @@ -513,7 +529,7 @@ public: RegOperand *GenLmbcParamLoad(int32 offset, uint32 byteSize, RegType regType, PrimType primType, AArch64reg baseRegno = RFP); RegOperand *LmbcStructReturnLoad(int32 offset); - Operand *GetBaseReg(const AArch64SymbolAlloc &symAlloc); + RegOperand *GetBaseReg(const SymbolAlloc &symAlloc) override; int32 GetBaseOffset(const SymbolAlloc &symAlloc) override; Operand &CreateCommentOperand(const std::string &s) const @@ -612,7 +628,7 @@ public: MemOperand &CreateStkTopOpnd(uint32 offset, uint32 size); MemOperand *CreateStackMemOpnd(regno_t preg, int32 offset, uint32 size); MemOperand *CreateMemOperand(uint32 size, RegOperand &base, ImmOperand &ofstOp, bool isVolatile, - MemOperand::AArch64AddressingMode mode = MemOperand::kAddrModeBOi) const; + MemOperand::AArch64AddressingMode mode = MemOperand::kAddrModeBOi) const; MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base, RegOperand *index, ImmOperand *offset, const MIRSymbol *symbol) const; MemOperand *CreateMemOperand(MemOperand::AArch64AddressingMode mode, uint32 size, RegOperand &base, @@ -887,8 +903,8 @@ private: kStateUnknown, }; Operand *rcc = nullptr; - Operand *vary = nullptr; - Operand *fsp = nullptr; /* used to point the address of local variables and formal parameters */ + RegOperand *vary = nullptr; + RegOperand *fsp = nullptr; /* used to point the address of local variables and formal parameters */ static CondOperand ccOperands[kCcLast]; static MovkLslOperandArray movkLslOperands; @@ -940,31 +956,30 @@ private: return (o.IsRegister() ? static_cast(o) : SelectCopy(o, sty, dty)); } - void CreateCallStructParamPassByStack(int32 symSize, const MIRSymbol *sym, RegOperand *addrOpnd, int32 baseOffset); - RegOperand *SelectParmListDreadAccessField(const MIRSymbol &sym, FieldID fieldID, const CCLocInfo &ploc, - int32 offset, uint32 parmNum); - void CreateCallStructParamPassByReg(regno_t reg, MemOperand &memOpnd, ListOperand &srcOpnds, fpParamState state); - void CreateCallStructParamMemcpy(const MIRSymbol &sym, uint32 structSize, int32 copyOffset, int32 fromOffset); - void CreateCallStructParamMemcpy(RegOperand &addrOpnd, uint32 structSize, int32 copyOffset, int32 fromOffset); - - RegOperand *CreateCallStructParamCopyToStack(uint32 numMemOp, const MIRSymbol *sym, RegOperand *addrOpd, - int32 copyOffset, int32 fromOffset, const CCLocInfo &ploc); - void SelectParmListDreadSmallAggregate(const MIRSymbol &sym, MIRType &structType, ListOperand &srcOpnds, - int32 offset, AArch64CallConvImpl &parmLocator, FieldID fieldID); - void SelectParmListIreadSmallAggregate(const IreadNode &iread, MIRType &structType, ListOperand &srcOpnds, - int32 offset, AArch64CallConvImpl &parmLocator); - void SelectParmListDreadLargeAggregate(const MIRSymbol &sym, MIRType &structType, ListOperand &srcOpnds, - AArch64CallConvImpl &parmLocator, int32 &structCopyOffset, int32 fromOffset); - void SelectParmListIreadLargeAggregate(const IreadNode &iread, MIRType &structType, ListOperand &srcOpnds, - AArch64CallConvImpl &parmLocator, int32 &structCopyOffset, int32 fromOffset); - void CreateCallStructMemcpyToParamReg(MIRType &structType, int32 structCopyOffset, AArch64CallConvImpl &parmLocator, - ListOperand &srcOpnds); - void SelectParmListForAggregate(BaseNode &argExpr, ListOperand &srcOpnds, AArch64CallConvImpl &parmLocator, - int32 &structCopyOffset); - size_t SelectParmListGetStructReturnSize(StmtNode &naryNode); bool MarkParmListCall(BaseNode &expr); - void SelectParmListPreprocessLargeStruct(BaseNode &argExpr, int32 &structCopyOffset); - void SelectParmListPreprocess(const StmtNode &naryNode, size_t start, std::set &specialArgs); + + struct ParamDesc { + ParamDesc(MIRType *type, BaseNode *expr, uint32 ofst = 0, bool copyed = false) + : mirType(type), argExpr(expr), offset(ofst), preCopyed(copyed) + { + } + MIRType *mirType = nullptr; + BaseNode *argExpr = nullptr; // expr node + uint32 offset = 0; // agg offset, for preCopyed struct, RSP-based offset + bool preCopyed = false; // for large struct, pre copyed to strack + bool isSpecialArg = false; // such as : tls + }; + + std::pair GetCalleeFunction(StmtNode &naryNode) const; + void SelectLibMemCopy(RegOperand &destOpnd, RegOperand &srcOpnd, uint32 structSize); + void SelectInsnMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size, bool isRefField = false, + BaseNode *destNode = nullptr, BaseNode *srcNode = nullptr); + void SelectMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size, bool isRefField = false, + BaseNode *destNode = nullptr, BaseNode *srcNode = nullptr); + void SelectParmListPreprocessForAggregate(BaseNode &argExpr, int32 &structCopyOffset, + std::vector &argsDesc, bool isArgUnused); + bool SelectParmListPreprocess(StmtNode &naryNode, size_t start, std::vector &argsDesc, + const MIRFunction *callee = nullptr); void SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative = false); void SelectParmListNotC(StmtNode &naryNode, ListOperand &srcOpnds); Operand *SelectClearStackCallParam(const AddrofNode &expr, int64 &offsetValue); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def index f5359e8a04d83e716f289a8ed286f8ef1ab442bd..0e5d6e1e9d8c6bede2170c4eb21273f80cd9dcaa 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_phases.def @@ -70,4 +70,5 @@ ADDTARGETPHASE("scheduling", CGOptions::DoSchedule()); ADDTARGETPHASE("alignanalysis", GetMIRModule()->IsCModule() && CGOptions::DoAlignAnalysis()); ADDTARGETPHASE("fixshortbranch", true); + ADDTARGETPHASE("cgirverify", CGOptions::DoCGIRVerify()); ADDTARGETPHASE("cgemit", true); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_proepilog.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_proepilog.h index 1301f7f7a00405da4de21b498a449d0b025b9f80..a46ebb13262de43509186367a5e04b9ea2332980 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_proepilog.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_proepilog.h @@ -28,8 +28,7 @@ using namespace maple; class AArch64GenProEpilog : public GenProEpilog { public: - AArch64GenProEpilog(CGFunc &func, MemPool &memPool) - : GenProEpilog(func), tmpAlloc(&memPool), exitBB2CallSitesMap(tmpAlloc.Adapter()) + AArch64GenProEpilog(CGFunc &func, MemPool &memPool) : GenProEpilog(func), tmpAlloc(&memPool) { useFP = func.UseFP(); if (func.GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) { @@ -37,7 +36,6 @@ public: } else { stackBaseReg = useFP ? R29 : RSP; } - exitBB2CallSitesMap.clear(); AArch64CGFunc &aarchCGFunc = static_cast(func); const MapleVector &calleeSavedRegs = aarchCGFunc.GetCalleeSavedRegs(); if (useFP) { @@ -51,77 +49,48 @@ public: } ~AArch64GenProEpilog() override = default; - bool TailCallOpt() override; bool NeedProEpilog() override; static MemOperand *SplitStpLdpOffsetForCalleeSavedWithAddInstruction(CGFunc &cgFunc, const MemOperand &mo, uint32 bitLen, - AArch64reg baseReg = AArch64reg::kRinvalid); - static void AppendInstructionPushPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, int offset); - static void AppendInstructionPushSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int offset); - static void AppendInstructionPopSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int offset); - static void AppendInstructionPopPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, int offset); + AArch64reg baseRegNum = AArch64reg::kRinvalid); + static void AppendInstructionPushPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, int32 offset); + static void AppendInstructionPushSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int32 offset); + static void AppendInstructionPopSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int32 offset); + static void AppendInstructionPopPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, int32 offset); void Run() override; private: - void GenStackGuard(BB &); - BB &GenStackGuardCheckInsn(BB &); - bool HasLoop(); - bool OptimizeTailBB(BB &bb, MapleSet &callInsns, const BB &exitBB) const; - void TailCallBBOpt(BB &bb, MapleSet &callInsns, BB &exitBB); - bool InsertOpndRegs(Operand &opnd, std::set &vecRegs) const; - bool InsertInsnRegs(Insn &insn, bool insetSource, std::set &vecSourceRegs, bool insertTarget, - std::set &vecTargetRegs); - bool FindRegs(Operand &insn, std::set &vecRegs) const; - bool BackwardFindDependency(BB &ifbb, std::set &vecReturnSourceReg, std::list &existingInsns, - std::list &moveInsns); - BB *IsolateFastPath(BB &); + AArch64reg GetStackGuardRegister(const BB &bb) const; + std::pair GetStackGuardCheckRegister(const BB &bb) const; + MemOperand *GetDownStack(); + RegOperand &GenStackGuard(AArch64reg regNO); + void AddStackGuard(BB &bb); + void GenStackGuardCheckInsn(BB &bb); + BB &GetOrGenStackGuardCheckFailBB(BB &bb); void AppendInstructionAllocateCallFrame(AArch64reg reg0, AArch64reg reg1, RegType rty); void AppendInstructionAllocateCallFrameDebug(AArch64reg reg0, AArch64reg reg1, RegType rty); void GeneratePushRegs(); void GeneratePushUnnamedVarargRegs(); - void AppendInstructionStackCheck(AArch64reg reg, RegType rty, int offset); - void GenerateProlog(BB &); + void AppendInstructionStackCheck(AArch64reg reg, RegType rty, int32 offset); + void GenerateProlog(BB &bb); void GenerateRet(BB &bb); bool TestPredsOfRetBB(const BB &exitBB); void AppendInstructionDeallocateCallFrame(AArch64reg reg0, AArch64reg reg1, RegType rty); void AppendInstructionDeallocateCallFrameDebug(AArch64reg reg0, AArch64reg reg1, RegType rty); void GeneratePopRegs(); - void AppendJump(const MIRSymbol &func); - void GenerateEpilog(BB &); - void GenerateEpilogForCleanup(BB &); - void ConvertToTailCalls(MapleSet &callInsnsMap); - Insn &CreateAndAppendInstructionForAllocateCallFrame(int64 argsToStkPassSize, AArch64reg reg0, AArch64reg reg1, + void AppendJump(const MIRSymbol &funcSymbol); + void GenerateEpilog(BB &bb); + void GenerateEpilogForCleanup(BB &bb); + void AppendBBtoEpilog(BB &epilogBB, BB &newBB); + Insn &CreateAndAppendInstructionForAllocateCallFrame(int64 fpToSpDistance, AArch64reg reg0, AArch64reg reg1, RegType rty); - Insn &AppendInstructionForAllocateOrDeallocateCallFrame(int64 argsToStkPassSize, AArch64reg reg0, AArch64reg reg1, + Insn &AppendInstructionForAllocateOrDeallocateCallFrame(int64 fpToSpDistance, AArch64reg reg0, AArch64reg reg1, RegType rty, bool isAllocate); - MapleMap> &GetExitBB2CallSitesMap() - { - return exitBB2CallSitesMap; - } - void SetCurTailcallExitBB(BB *bb) - { - curTailcallExitBB = bb; - } - BB *GetCurTailcallExitBB() - { - return curTailcallExitBB; - } - void SetFastPathReturnBB(BB *bb) - { - fastPathReturnBB = bb; - } - BB *GetFastPathReturnBB() - { - return fastPathReturnBB; - } MapleAllocator tmpAlloc; static constexpr const int32 kOffset8MemPos = 8; static constexpr const int32 kOffset16MemPos = 16; - MapleMap> exitBB2CallSitesMap; - BB *curTailcallExitBB = nullptr; - BB *fastPathReturnBB = nullptr; - bool useFP = true; + bool useFP = false; // To be compatible with previous code more easily,we use storeFP boolean to indicate the case // (1) use FP to address // (2) FP is clobbered @@ -129,6 +98,7 @@ private: bool storeFP = false; /* frame pointer(x29) is available as a general-purpose register if useFP is set as false */ AArch64reg stackBaseReg = RFP; + BB *stackChkFailBB = nullptr; // only one stack check fail BB is need }; } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/call_conv.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/call_conv.h index 6410755bc733373af265f706822aabcbf4b3ff22..059a829c5bdd72a85291fd386d9c1498fc409bae 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/call_conv.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/call_conv.h @@ -37,6 +37,24 @@ struct CCLocInfo { PrimType primTypeOfReg1; /* the primitive type stored in reg1 */ PrimType primTypeOfReg2; PrimType primTypeOfReg3; + + void Clear() + { + reg0 = kInvalidRegNO; + reg1 = kInvalidRegNO; + reg2 = kInvalidRegNO; + reg3 = kInvalidRegNO; + memOffset = 0; + memSize = 0; + fpSize = 0; + numFpPureRegs = 0; + regCount = 0; + primTypeOfReg0 = PTY_begin; + primTypeOfReg1 = PTY_begin; + primTypeOfReg2 = PTY_begin; + primTypeOfReg3 = PTY_begin; + } + uint8 GetRegCount() const { return regCount; @@ -243,10 +261,10 @@ public: ~CCImpl() = default; - virtual int32 LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, - MIRFunction *func = nullptr) = 0; + virtual uint64 LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst = false, + MIRFuncType *tFunc = nullptr) = 0; - virtual int32 LocateRetVal(MIRType &retType, CCLocInfo &ploc) = 0; + virtual void LocateRetVal(const MIRType &retType, CCLocInfo &ploc) = 0; void InitCCLocInfo(CCLocInfo &pLoc) const { @@ -260,8 +278,6 @@ public: return; }; - virtual void InitReturnInfo(MIRType &retTy, CCLocInfo &pLoc) = 0; - virtual void SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc) const = 0; virtual void Init() = 0; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cfi.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cfi.h index 8ba347dae044d171a9f9d005af1a9b5eb3c0a0f0..58fd90e55cba4fbbf9ad7f33becc87c7da367ae7 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cfi.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cfi.h @@ -92,9 +92,7 @@ public: void Dump() const override; -#if DEBUG - void Check() const override; -#endif + bool CheckMD() const override; bool IsCfiInsn() const override { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h index 3d8514ae8204bb872ea728dfb040cdefec800c46..9071c4b050d86cf3e56e913502b06c9d2aa0834a 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cg_option.h @@ -1001,7 +1001,7 @@ public: { return targetArch == "aarch64"; }; - + static void EnableVregRename() { doVregRename = true; @@ -1596,6 +1596,10 @@ public: return doOptimizedFrameLayout; } + static bool DoCGIRVerify() + { + return doCgirVerify; + } private: std::vector phaseSequence; EmitMemoryManager emitMemoryManager; @@ -1706,6 +1710,7 @@ private: static uint32 jumpAlignPow; static uint32 funcAlignPow; static bool doOptimizedFrameLayout; + static bool doCgirVerify; }; } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h index 07efc58f60c8578b21c42dac6093d0a72c960f4a..4abe4c0ea4591757da3f005cb70e9c46db233825 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgbb.h @@ -681,9 +681,9 @@ public: { return loop; } - void SetLoop(CGFuncLoops &arg) + void SetLoop(CGFuncLoops *arg) { - loop = &arg; + loop = arg; } bool GetLiveInChange() const { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h index 86e911f2184bd1da39bd48158b65631de5cc1b71..35dbb1da9675443b9c94129873ae7c2c64dea16e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/cgfunc.h @@ -83,6 +83,74 @@ private: MapleSet reuseSpillLocMem; }; +// Memory read/write node helper - such as: iread, dread, iassign, dassign +class MemRWNodeHelper { +public: + MemRWNodeHelper(const BaseNode &node, MIRFunction &mirFunc, const BECommon &beCommon) + { + GetMemRWNodeBaseInfo(node, mirFunc); + GetTrueMirInfo(beCommon); + } + ~MemRWNodeHelper() = default; + + FieldID GetFieldID() const + { + return fieldId; + } + + const MIRType *GetMIRType() const + { + return mirType; + } + + MIRType *GetMIRType() + { + return mirType; + } + + int32 GetByteOffset() const + { + return byteOffset; + } + + uint32 GetMemSize() const + { + return memSize; + } + + PrimType GetPrimType() const + { + return primType; + } + + bool IsRefField() const + { + return isRefField; + } + + const MIRSymbol *GetSymbol() const + { + return symbol; + } + + MIRSymbol *GetSymbol() + { + return symbol; + } + +private: + FieldID fieldId = FieldID(0); // fieldId from node + MIRType *mirType = nullptr; // true mirType + MIRSymbol *symbol = nullptr; // date sym, for dread/dassign + int32 byteOffset = 0; + uint32 memSize = 0; + PrimType primType = PTY_unknown; + bool isRefField = false; // for java + + void GetMemRWNodeBaseInfo(const BaseNode &node, MIRFunction &mirFunc); + void GetTrueMirInfo(const BECommon &beCommon); +}; + #if TARGARM32 class LiveRange; #endif /* TARGARM32 */ @@ -323,7 +391,6 @@ public: virtual Operand *SelectLazyLoadStatic(MIRSymbol &st, int64 offset, PrimType primType) = 0; virtual Operand *SelectLoadArrayClassCache(MIRSymbol &st, int64 offset, PrimType primType) = 0; virtual void GenerateYieldpoint(BB &bb) = 0; - virtual Operand &ProcessReturnReg(PrimType primType, int32 sReg) = 0; virtual Operand &GetOrCreateRflag() = 0; virtual const Operand *GetRflag() const = 0; @@ -336,6 +403,7 @@ public: virtual RegOperand &GetOrCreateVirtualRegisterOperand(RegOperand ®Opnd) = 0; virtual RegOperand &GetOrCreateFramePointerRegOperand() = 0; virtual RegOperand &GetOrCreateStackBaseRegOperand() = 0; + virtual RegOperand *GetBaseReg(const SymbolAlloc &symAlloc) = 0; virtual int32 GetBaseOffset(const SymbolAlloc &symbolAlloc) = 0; virtual RegOperand &GetZeroOpnd(uint32 size) = 0; virtual Operand &CreateCfiRegOperand(uint32 reg, uint32 size) = 0; @@ -512,12 +580,12 @@ public: size = k4ByteSize; } #if TARGAARCH64 - if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) { - /* cannot handle 128 size register */ - if (regType == kRegTyInt && size > k8ByteSize) { - size = k8ByteSize; + if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) { + /* cannot handle 128 size register */ + if (regType == kRegTyInt && size > k8ByteSize) { + size = k8ByteSize; + } } - } #endif DEBUG_ASSERT(size == k4ByteSize || size == k8ByteSize || size == k16ByteSize, "check size"); #endif @@ -1203,6 +1271,16 @@ public: lmbcTotalArgs = 0; } + void SetSpSaveReg(regno_t reg) + { + spSaveReg = reg; + } + + regno_t GetSpSaveReg() const + { + return spSaveReg; + } + MapleVector &GetAllBBs() { return bbVec; @@ -1511,6 +1589,16 @@ public: return stackProtectInfo; } + void SetNeedStackProtect(bool val) + { + needStackProtect = val; + } + + bool GetNeedStackProtect() const + { + return needStackProtect; + } + CallConvKind GetCurCallConvKind() const { return callingConventionKind; @@ -1626,9 +1714,8 @@ protected: RegType regType = vRegNode.GetType(); DEBUG_ASSERT(regType == kRegTyInt || regType == kRegTyFloat, ""); uint32 size = vRegNode.GetSize(); /* in bytes */ - DEBUG_ASSERT(size == sizeof(int32) || size == sizeof(int64), ""); - return (regType == kRegTyInt ? (size == sizeof(int32) ? PTY_i32 : PTY_i64) - : (size == sizeof(float) ? PTY_f32 : PTY_f64)); + return (regType == kRegTyInt ? (size <= sizeof(int32) ? PTY_i32 : PTY_i64) + : (size <= sizeof(float) ? PTY_f32 : PTY_f64)); } int64 GetPseudoRegisterSpillLocation(PregIdx idx) @@ -1653,10 +1740,10 @@ protected: } /* See if the symbol is a structure parameter that requires a copy. */ - bool IsParamStructCopy(const MIRSymbol &symbol) + bool IsParamStructCopy(const MIRSymbol &symbol) const { - if (symbol.GetStorageClass() == kScFormal && - GetBecommon().GetTypeSize(symbol.GetTyIdx().GetIdx()) > k16ByteSize) { + auto *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(symbol.GetTyIdx()); + if (symbol.GetStorageClass() == kScFormal && IsParamStructCopyToMemory(*mirType)) { return true; } return false; @@ -1718,7 +1805,7 @@ private: uint32 bbCnt = 0; uint32 labelIdx = 0; /* local label index number */ LabelNode *startLabel = nullptr; /* start label of the function */ - LabelNode *returnLabel = nullptr; /* return label of the function */ + LabelNode *returnLabel = nullptr; /* return label of the function */ LabelNode *cleanupLabel = nullptr; /* label to indicate the entry of cleanup code. */ LabelNode *endLabel = nullptr; /* end label of the function */ @@ -1755,6 +1842,7 @@ private: CGCFG *theCFG = nullptr; FuncEmitInfo *funcEmitInfo = nullptr; uint32 nextSpillLocation = 0; + regno_t spSaveReg = 0; const MapleString shortFuncName; bool hasAsm = false; @@ -1765,6 +1853,7 @@ private: /* save stack protect kinds which can trigger stack protect */ uint8 stackProtectInfo = 0; + bool needStackProtect = false; // mark exitBB is unreachable bool exitBBLost = false; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/dbg.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/dbg.h index 56b834f8c6b5d7dd0e248889a0042c823a98f637..0cde8373462419915f56a078ce09e1ff3f21d612 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/dbg.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/dbg.h @@ -71,9 +71,7 @@ public: void Dump() const override; -#if DEBUG - void Check() const override; -#endif + bool CheckMD() const override; bool IsTargetInsn() const override { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/insn.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/insn.h index 7ef3ced44d883a34dc8ba8d192b68aa2acd526fb..647ff905c0c1782f01e402576d8459c88cfe86ff 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/insn.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/insn.h @@ -377,9 +377,7 @@ public: virtual void Dump() const; -#if DEBUG - virtual void Check() const; -#endif + virtual bool CheckMD() const; void SetComment(const std::string &str) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/proepilog.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/proepilog.h index 33ca03e4d83da60640c008ca867adbc6e7417372..dac324605472165fc0bcc313487cf915f9341e6e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/proepilog.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/proepilog.h @@ -33,11 +33,6 @@ public: return "generateproepilog"; } - virtual bool TailCallOpt() - { - return false; - } - virtual bool NeedProEpilog() { return true; @@ -56,17 +51,9 @@ public: return offsetFromCfa; } - Insn *InsertCFIDefCfaOffset(int32 &cfiOffset, Insn &insertAfter); /* cfiOffset in-out */ - protected: - /* check if the current funtion need stack protect code */ - void NeedStackProtect(); - /* check if a type include array */ - bool IncludeArray(const MIRType &type) const; - CGFunc &cgFunc; int64 offsetFromCfa = 0; /* SP offset from Call Frame Address */ - bool stackProtect = false; }; } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_args.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_args.h index 116ebabf4732a81bcac548784138bb4a51e4ba52..e815e2655468025e0bfdfe29be76fe39134d0b31 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_args.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_args.h @@ -28,6 +28,7 @@ struct X64ArgInfo { X64reg reg; MIRType *mirTy; uint32 symSize; + uint32 stkSize; RegType regType; MIRSymbol *sym; const X64SymbolAlloc *symLoc; @@ -48,7 +49,7 @@ private: std::map &pairReg, std::vector &numFpRegs, std::vector &fpSize) const; X64ArgInfo GetArgInfo(std::map &argsList, uint32 argIndex, std::vector &numFpRegs, - std::vector &fpSize) const; + std::vector &fpSize) const; void GenerateMovInsn(X64ArgInfo &argInfo, X64reg reg2); void MoveRegisterArgs(); void MoveVRegisterArgs(); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_call_conv.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_call_conv.h index a02bfc1a32deb14762bb92edf9dfccc21a3b5cff..be89e022e3c3244ab2a0dbe8f3c18537064d55fe 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_call_conv.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_call_conv.h @@ -232,13 +232,12 @@ private: X64reg AllocateSIMDFPReturnRegister() { - return (nextFloatRetRegNO < kNumFloatReturnRegs) ? - kFloatReturnRegs[nextFloatRetRegNO++] : X64reg::kRinvalid; + return (nextFloatRetRegNO < kNumFloatReturnRegs) ? kFloatReturnRegs[nextFloatRetRegNO++] : X64reg::kRinvalid; } BECommon &beCommon; CallConvKind convKind = kCCall; - uint64 paramNum = 0; /* number of all types of parameters processed so far */ + uint64 paramNum = 0; /* number of all types of parameters processed so far */ uint32 nextGeneralParmRegNO = 0; /* number of integer parameters processed so far */ uint32 nextGeneralReturnRegNO = 0; /* number of integer return processed so far */ uint32 nextStackArgAdress = 0; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_cgfunc.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_cgfunc.h index a0521f6d4d1031381c8c00d1059f3ac5f96f024c..ee5b98194e2c2e9d0f26382754113cae9c66a90a 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_cgfunc.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_cgfunc.h @@ -164,7 +164,6 @@ public: Operand *SelectLazyLoadStatic(MIRSymbol &st, int64 offset, PrimType primType) override; Operand *SelectLoadArrayClassCache(MIRSymbol &st, int64 offset, PrimType primType) override; void GenerateYieldpoint(BB &bb) override; - Operand &ProcessReturnReg(PrimType primType, int32 sReg) override; Operand &GetOrCreateRflag() override; const Operand *GetRflag() const override; const Operand *GetFloatRflag() const override; @@ -228,7 +227,7 @@ public: MemOperand *GetPseudoRegisterSpillMemoryOperand(PregIdx idx) override; int32 GetBaseOffset(const SymbolAlloc &symbolAlloc) override; - RegOperand *GetBaseReg(const SymbolAlloc &symAlloc); + RegOperand *GetBaseReg(const SymbolAlloc &symAlloc) override; void AddtoCalleeSaved(regno_t reg) override { diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_phases.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_phases.def index 40f7fa05c9db290214c8f2e628f8ef103d09f821..df9f5e035d538f29d82ba5711d07b9c5f1be9e4a 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_phases.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_phases.def @@ -25,5 +25,6 @@ ADDTARGETPHASE("postcfgo", false); ADDTARGETPHASE("cgpostpeephole", false); ADDTARGETPHASE("generateproepilog", true); - /* ASM EMIT */ + ADDTARGETPHASE("cgirverify", CGOptions::DoCGIRVerify()); + /* ASM or OBJ EMIT */ ADDTARGETPHASE("cgemit", true); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_proepilog.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_proepilog.h index c2a0474e3d51827589fd78a36e3312912dd304c0..0918e7da659d59f717a7abeb2cee29bb4090ed92 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_proepilog.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_proepilog.h @@ -26,7 +26,6 @@ public: explicit X64GenProEpilog(CGFunc &func) : GenProEpilog(func) {} ~X64GenProEpilog() override = default; - bool TailCallOpt() override; bool NeedProEpilog() override; void Run() override; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp index 7c3c0bcebe817a8e0ef220d788011243ba439669..e30eb21967fbb0a877ae78fde24fa28393934533 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp @@ -64,7 +64,7 @@ static uint32 TryAllocInPaddingSlots(std::list paddingSlots[], uint32 fi size_t paddingSlotsLength) { CHECK_FATAL(paddingSlotsLength > 0, "expect paddingSlotsLength > 0"); - if (fieldSize > 4) { // padding slots are just for size 1/2/4 bytes + if (fieldSize > 4) { // padding slots are just for size 1/2/4 bytes return 0; } @@ -259,7 +259,7 @@ void BECommon::ComputeClassTypeSizesAligns(MIRType &ty, const TyIdx &tyIdx, uint * a list of un-occupied (small size) slots available for insertion * so far, just for 1, 2, 4 bytes types (map to array index 0, 1, 2) */ - std::list paddingSlots[3]; // padding slots are just 3 types for size 1/2/4 bytes + std::list paddingSlots[3]; // padding slots are just 3 types for size 1/2/4 bytes /* process fields */ AppendStructFieldCount(tyIdx, fields.size()); if (fields.size() == 0 && mirModule.IsCModule()) { @@ -564,6 +564,19 @@ void BECommon::GenObjSize(const MIRClassType &classType, FILE &outFile) fprintf(&outFile, "__MRT_CLASS(%s, %" PRIu64 ", %s)\n", className.c_str(), objSize, parentName); } +// compute the offset of the field given by fieldID within the java class +FieldInfo BECommon::GetJClassFieldOffset(MIRStructType &classType, FieldID fieldID) const +{ + CHECK_FATAL(fieldID <= GetStructFieldCount(classType.GetTypeIndex()), "GetFieldOFfset: fieldID too large"); + if (fieldID == 0) { + return {0, 0}; + } + CHECK_FATAL(HasJClassLayout(static_cast(classType)), "Cannot found java class layout information"); + const JClassLayout &layout = GetJClassLayout(static_cast(classType)); + CHECK_FATAL(static_cast(fieldID) - 1 < layout.size(), "subscript out of range"); + return {static_cast(layout[static_cast(fieldID) - 1].GetOffset()), 0}; +} + /* * compute the offset of the field given by fieldID within the structure type * structy; it returns the answer in the pair (byteoffset, bitoffset) such that @@ -773,7 +786,7 @@ BaseNode *BECommon::GetAddressOfNode(const BaseNode &node) } uint32 index = static_cast(GlobalTables::GetTypeTable().GetTypeTable().at(iNode.GetTyIdx())) - ->GetPointedTyIdx(); + ->GetPointedTyIdx(); MIRType *pointedType = GlobalTables::GetTypeTable().GetTypeTable().at(index); std::pair byteBitOffset = GetFieldOffset(static_cast(*pointedType), iNode.GetFieldID()); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp index a23f525189275c3a0f500a46bb3ddabcaada2c65..ff2e25ddfad77aed3bafcc72b5d87db749bd07a6 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp @@ -900,10 +900,6 @@ BlockNode *CGLowerer::LowerReturnStructUsingFakeParm(NaryStmtNode &retNode) IassignNode *iassign = mirModule.CurFuncCodeMemPool()->New(); iassign->SetTyIdx(retTy->GetTypeIndex()); DEBUG_ASSERT(opnd0 != nullptr, "opnd0 should not be nullptr"); - if ((beCommon.GetTypeSize(retTy->GetPointedTyIdx().GetIdx()) <= k16ByteSize) && (opnd0->GetPrimType() == PTY_agg)) { - /* struct goes into register. */ - curFunc->SetStructReturnedInRegs(); - } iassign->SetFieldID(0); iassign->SetRHS(opnd0); if (retSt->IsPreg()) { @@ -1208,7 +1204,7 @@ StmtNode *CGLowerer::GenIcallNode(PUIdx &funcCalled, IcallNode &origCall) if (origCall.GetOpCode() == OP_icallassigned) { newCall = mirModule.GetMIRBuilder()->CreateStmtIcall(origCall.GetNopnd()); } else { - newCall = mirModule.GetMIRBuilder()->CreateStmtIcallproto(origCall.GetNopnd()); + newCall = mirModule.GetMIRBuilder()->CreateStmtIcallproto(origCall.GetNopnd(), origCall.GetRetTyIdx()); newCall->SetRetTyIdx(static_cast(origCall).GetRetTyIdx()); } newCall->SetDeoptBundleInfo(origCall.GetDeoptBundleInfo()); @@ -1295,7 +1291,7 @@ BlockNode *CGLowerer::GenBlockNode(StmtNode &newCall, const CallReturnVector &p2 blk->AddStatement(cmnt); } CHECK_FATAL(dStmt == nullptr || dStmt->GetNext() == nullptr, "make sure dStmt or dStmt's next is nullptr"); - LowerCallStmt(newCall, dStmt, *blk, retType, uselvar ? true : false, opcode == OP_intrinsiccallassigned); + LowerCallStmt(newCall, dStmt, *blk, retType, uselvar, opcode == OP_intrinsiccallassigned); if (!uselvar && dStmt != nullptr) { dStmt->SetSrcPos(newCall.GetSrcPos()); blk->AddStatement(dStmt); @@ -1485,14 +1481,10 @@ static PrimType IsStructElementSame(MIRType *ty) } #endif -// return true if successfully lowered; nextStmt is in/out, and is made to point -// to its following statement if lowering of the struct return is successful -bool CGLowerer::LowerStructReturn(BlockNode &newBlk, StmtNode *stmt, StmtNode *&nextStmt, bool &lvar, BlockNode *oldBlk) +// return true if successfully lowered +bool CGLowerer::LowerStructReturn(BlockNode &newBlk, StmtNode &stmt, bool &lvar) { - if (!nextStmt) { - return false; - } - CallReturnVector *p2nrets = stmt->GetCallReturnVector(); + CallReturnVector *p2nrets = stmt.GetCallReturnVector(); if (p2nrets->size() == 0) { return false; } @@ -1504,236 +1496,175 @@ bool CGLowerer::LowerStructReturn(BlockNode &newBlk, StmtNode *stmt, StmtNode *& if (retSym->GetType()->GetPrimType() != PTY_agg) { return false; } - if (nextStmt->op != OP_dassign) { - // introduce a temporary and insert a dassign whose rhs is this temporary - // and whose lhs is retSym - MIRSymbol *temp = CreateNewRetVar(*retSym->GetType(), kUserRetValPrefix); - BaseNode *rhs = mirModule.GetMIRBuilder()->CreateExprDread(*temp->GetType(), 0, *temp); - DassignNode *dass = - mirModule.GetMIRBuilder()->CreateStmtDassign(retPair.first, retPair.second.GetFieldID(), rhs); - oldBlk->InsertBefore(nextStmt, dass); - nextStmt = dass; - // update CallReturnVector to the new temporary - (*p2nrets)[0].first = temp->GetStIdx(); - (*p2nrets)[0].second.SetFieldID(0); - } - // now, it is certain that nextStmt is a dassign - BaseNode *bnode = static_cast(nextStmt)->GetRHS(); - if (bnode->GetOpCode() != OP_dread) { + + if (IsReturnInMemory(*retSym->GetType())) { + lvar = true; + } else if (!LowerStructReturnInRegs(newBlk, stmt, *retSym)) { return false; } - DreadNode *dnode = static_cast(bnode); - MIRType *dtype = mirModule.CurFunction()->GetLocalOrGlobalSymbol(dnode->GetStIdx())->GetType(); -#if TARGAARCH64 - if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) { - PrimType ty = IsStructElementSame(dtype); - if (ty == PTY_f32 || ty == PTY_f64 || IsPrimitiveVector(ty)) { - return false; + return true; +} + +bool CGLowerer::LowerStructReturnInRegs(BlockNode &newBlk, StmtNode &stmt, const MIRSymbol &retSym) +{ + // lower callassigned -> call + if (stmt.GetOpCode() == OP_callassigned) { + auto &callNode = static_cast(stmt); + for (size_t i = 0; i < callNode.GetNopndSize(); ++i) { + auto *newOpnd = LowerExpr(callNode, *callNode.GetNopndAt(i), newBlk); + callNode.SetOpnd(newOpnd, i); } - } -#endif - if (dnode->GetPrimType() != PTY_agg) { - return false; - } - CallReturnPair pair = (*p2nrets)[0]; - if (pair.first != dnode->GetStIdx() || pair.second.GetFieldID() != dnode->GetFieldID()) { - return false; - } - auto *dnodeStmt = static_cast(nextStmt); - if (dnodeStmt->GetFieldID() != 0) { - return false; - } - if (dtype->GetSize() > k16ByteSize) { - (*p2nrets)[0].first = dnodeStmt->GetStIdx(); - (*p2nrets)[0].second.SetFieldID(dnodeStmt->GetFieldID()); - lvar = true; - // set ATTR_firstarg_return for callee - if (stmt->GetOpCode() == OP_callassigned) { - CallNode *callNode = static_cast(stmt); - MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx()); - f->SetFirstArgReturn(); - f->GetMIRFuncType()->SetFirstArgReturn(); - } else { - // for icall, front-end already set ATTR_firstarg_return + auto *callStmt = mirModule.GetMIRBuilder()->CreateStmtCall(callNode.GetPUIdx(), callNode.GetNopnd()); + callStmt->SetSrcPos(callNode.GetSrcPos()); + newBlk.AddStatement(callStmt); + } else if (stmt.GetOpCode() == OP_icallassigned || stmt.GetOpCode() == OP_icallprotoassigned) { + auto &icallNode = static_cast(stmt); + for (size_t i = 0; i < icallNode.GetNopndSize(); ++i) { + auto *newOpnd = LowerExpr(icallNode, *icallNode.GetNopndAt(i), newBlk); + icallNode.SetOpnd(newOpnd, i); } - } else { /* struct <= 16 passed in regs lowered into - call &foo - regassign u64 %1 (regread u64 %%retval0) - regassign ptr %2 (addrof ptr $s) - iassign <* u64> 0 (regread ptr %2, regread u64 %1) */ - MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(dnodeStmt->GetStIdx()); - auto *structType = static_cast(symbol->GetType()); - auto size = static_cast(structType->GetSize()); - if (stmt->GetOpCode() == OP_callassigned) { - auto *callNode = static_cast(stmt); - for (size_t i = 0; i < callNode->GetNopndSize(); ++i) { - BaseNode *newOpnd = LowerExpr(*callNode, *callNode->GetNopndAt(i), newBlk); - callNode->SetOpnd(newOpnd, i); - } - CallNode *callStmt = mirModule.GetMIRBuilder()->CreateStmtCall(callNode->GetPUIdx(), callNode->GetNopnd()); - callStmt->SetSrcPos(callNode->GetSrcPos()); - newBlk.AddStatement(callStmt); - } else if (stmt->GetOpCode() == OP_icallassigned || stmt->GetOpCode() == OP_icallprotoassigned) { - auto *icallNode = static_cast(stmt); - for (size_t i = 0; i < icallNode->GetNopndSize(); ++i) { - BaseNode *newOpnd = LowerExpr(*icallNode, *icallNode->GetNopndAt(i), newBlk); - icallNode->SetOpnd(newOpnd, i); - } - IcallNode *icallStmt = nullptr; - if (stmt->GetOpCode() == OP_icallassigned) { - icallStmt = mirModule.GetMIRBuilder()->CreateStmtIcall(icallNode->GetNopnd()); - } else { - icallStmt = mirModule.GetMIRBuilder()->CreateStmtIcallproto(icallNode->GetNopnd()); - icallStmt->SetRetTyIdx(icallNode->GetRetTyIdx()); - } - icallStmt->SetSrcPos(icallNode->GetSrcPos()); - newBlk.AddStatement(icallStmt); + IcallNode *icallStmt = nullptr; + if (stmt.GetOpCode() == OP_icallassigned) { + icallStmt = mirModule.GetMIRBuilder()->CreateStmtIcall(icallNode.GetNopnd()); } else { - return false; + icallStmt = mirModule.GetMIRBuilder()->CreateStmtIcallproto(icallNode.GetNopnd(), icallNode.GetRetTyIdx()); } + icallStmt->SetSrcPos(icallNode.GetSrcPos()); + newBlk.AddStatement(icallStmt); + } else { + return false; + } - uint32 origSize = size; - PregIdx pIdxR, pIdx1R, pIdx2R; - StmtNode *aStmt = nullptr; - RegreadNode *reg = nullptr; - - /* save x0 */ - reg = mirBuilder->CreateExprRegread(PTY_u64, -kSregRetval0); - pIdx1R = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); - aStmt = mirBuilder->CreateStmtRegassign(PTY_u64, pIdx1R, reg); - newBlk.AddStatement(aStmt); - - /* save x1 */ - if (origSize > k8ByteSize) { - reg = mirBuilder->CreateExprRegread(PTY_u64, -kSregRetval1); - pIdx2R = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); - aStmt = mirBuilder->CreateStmtRegassign(PTY_u64, pIdx2R, reg); - newBlk.AddStatement(aStmt); + if (Triple::GetTriple().IsAarch64BeOrLe()) { +#if TARGAARCH64 + PrimType primType = PTY_begin; + size_t elemNum = 0; + if (IsHomogeneousAggregates(*retSym.GetType(), primType, elemNum)) { + LowerStructReturnInFpRegs(newBlk, stmt, retSym, primType, elemNum); + } else { + LowerStructReturnInGpRegs(newBlk, stmt, retSym); } +#endif + } else { + LowerStructReturnInGpRegs(newBlk, stmt, retSym); + } + return true; +} - /* save &s */ - BaseNode *regAddr = mirBuilder->CreateExprAddrof(0, *symbol); - PregIdx pIdxL = GetCurrentFunc()->GetPregTab()->CreatePreg(GetLoweredPtrType()); - aStmt = mirBuilder->CreateStmtRegassign(PTY_a64, pIdxL, regAddr); +// struct passed in gpregs, lowered into +// call &foo +// regassign u64 %1 (regread u64 %%retval0) +// regassign ptr %2 (addrof ptr $s) +// iassign <* u64> 0 (regread ptr %2, regread u64 %1) +void CGLowerer::LowerStructReturnInGpRegs(BlockNode &newBlk, const StmtNode &stmt, const MIRSymbol &symbol) +{ + auto size = static_cast(symbol.GetType()->GetSize()); + if (size == 0) { + return; + } + // save retval0, retval1 + PregIdx pIdx1R = 0; + PregIdx pIdx2R = 0; + auto genRetvalSave = [this, &newBlk](PregIdx &pIdx, SpecialReg sreg) { + auto *regreadNode = mirBuilder->CreateExprRegread(PTY_u64, -sreg); + pIdx = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); + auto *aStmt = mirBuilder->CreateStmtRegassign(PTY_u64, pIdx, regreadNode); newBlk.AddStatement(aStmt); + }; + genRetvalSave(pIdx1R, kSregRetval0); + if (size > k8ByteSize) { + genRetvalSave(pIdx2R, kSregRetval1); + } + // save &s + BaseNode *regAddr = mirBuilder->CreateExprAddrof(0, symbol); + LowerTypePtr(*regAddr); + PregIdx pIdxL = GetCurrentFunc()->GetPregTab()->CreatePreg(GetLoweredPtrType()); + auto *aStmt = mirBuilder->CreateStmtRegassign(PTY_a64, pIdxL, regAddr); + newBlk.AddStatement(aStmt); + + // str retval to &s + for (uint32 curSize = 0; curSize < size;) { + // calc addr + BaseNode *addrNode = mirBuilder->CreateExprRegread(GetLoweredPtrType(), pIdxL); + if (curSize != 0) { + MIRType *addrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetLoweredPtrType()); + addrNode = + mirBuilder->CreateExprBinary(OP_add, *addrType, addrNode, mirBuilder->CreateIntConst(curSize, PTY_i32)); + } - uint32 curSize = 0; - PregIdx pIdxS; - while (size) { - pIdxR = pIdx1R; - if (curSize >= k8ByteSize) { - pIdxR = pIdx2R; - } - BaseNode *addr; - BaseNode *shift; - BaseNode *regreadExp; - if (origSize != size) { - MIRType *addrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetLoweredPtrType()); - addr = mirBuilder->CreateExprBinary(OP_add, *addrType, - mirBuilder->CreateExprRegread(GetLoweredPtrType(), pIdxL), - mirBuilder->CreateIntConst(origSize - size, PTY_i32)); - } else { - addr = mirBuilder->CreateExprRegread(GetLoweredPtrType(), pIdxL); + PregIdx pIdxR = (curSize < k8ByteSize) ? pIdx1R : pIdx2R; + uint32 strSize = size - curSize; + // gen str retval to &s + offset + auto genStrRetval2Memory = [this, &newBlk, &addrNode, &curSize, &pIdxR](PrimType primType) { + uint32 shiftSize = (curSize * kBitsPerByte) % k64BitSize; + if (CGOptions::IsBigEndian()) { + shiftSize = k64BitSize - GetPrimTypeBitSize(primType) + shiftSize; } - if (size >= k8ByteSize) { - aStmt = mirBuilder->CreateStmtIassign( - *beCommon.BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetUInt64()), 0, addr, - mirBuilder->CreateExprRegread(PTY_u64, pIdxR)); - size -= k8ByteSize; - curSize += k8ByteSize; - } else if (size >= k4ByteSize) { - MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(PTY_u64); - - if (CGOptions::IsBigEndian()) { - regreadExp = - mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k64BitSize - k32BitSize, PTY_i32)); - } else { - regreadExp = mirBuilder->CreateExprRegread(PTY_u32, pIdxR); - } - - aStmt = mirBuilder->CreateStmtIassign( - *beCommon.BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetUInt32()), 0, addr, regreadExp); - - if (CGOptions::IsBigEndian()) { - shift = mirBuilder->CreateExprBinary(OP_shl, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k32BitSize, PTY_i32)); - } else { - shift = mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k32BitSize, PTY_i32)); - } - - pIdxS = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); - StmtNode *sStmp = mirBuilder->CreateStmtRegassign(PTY_u64, pIdxS, shift); - - pIdx1R = pIdx2R = pIdxS; - newBlk.AddStatement(sStmp); - size -= k4ByteSize; - curSize += k4ByteSize; - } else if (size >= k2ByteSize) { - MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(PTY_u64); - - if (CGOptions::IsBigEndian()) { - regreadExp = - mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k64BitSize - k16BitSize, PTY_i32)); - } else { - regreadExp = mirBuilder->CreateExprRegread(PTY_u16, pIdxR); - } - - aStmt = mirBuilder->CreateStmtIassign( - *beCommon.BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetUInt16()), 0, addr, regreadExp); - - if (CGOptions::IsBigEndian()) { - shift = mirBuilder->CreateExprBinary(OP_shl, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k64BitSize - k16BitSize, PTY_i32)); - } else { - shift = mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k16BitSize, PTY_i32)); - } - - pIdxS = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); - StmtNode *sStmp = mirBuilder->CreateStmtRegassign(PTY_u64, pIdxS, shift); - - pIdx1R = pIdx2R = pIdxS; - newBlk.AddStatement(sStmp); - size -= k2ByteSize; - curSize += k2ByteSize; - } else { + BaseNode *regreadExp = mirBuilder->CreateExprRegread(PTY_u64, pIdxR); + if (shiftSize != 0) { MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(PTY_u64); + regreadExp = mirBuilder->CreateExprBinary(OP_lshr, *type, regreadExp, + mirBuilder->CreateIntConst(shiftSize, PTY_i32)); + } + auto *pointedType = GlobalTables::GetTypeTable().GetPrimType(primType); + auto *iassignStmt = mirBuilder->CreateStmtIassign(*beCommon.BeGetOrCreatePointerType(*pointedType), 0, + addrNode, regreadExp); + newBlk.AddStatement(iassignStmt); + curSize += GetPrimTypeSize(primType); + }; + if (strSize >= k8ByteSize) { + genStrRetval2Memory(PTY_u64); + } else if (strSize >= k4ByteSize) { + genStrRetval2Memory(PTY_u32); + } else if (strSize >= k2ByteSize) { + genStrRetval2Memory(PTY_u16); + } else { + genStrRetval2Memory(PTY_u8); + } + } +} - if (CGOptions::IsBigEndian()) { - regreadExp = - mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k64BitSize - k8BitSize, PTY_i32)); - } else { - regreadExp = mirBuilder->CreateExprRegread(PTY_u8, pIdxR); - } - - aStmt = mirBuilder->CreateStmtIassign( - *beCommon.BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetUInt8()), 0, addr, regreadExp); - - if (CGOptions::IsBigEndian()) { - shift = mirBuilder->CreateExprBinary(OP_shl, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k64BitSize - k8BitSize, PTY_i32)); - } else { - shift = mirBuilder->CreateExprBinary(OP_lshr, *type, mirBuilder->CreateExprRegread(PTY_u64, pIdxR), - mirBuilder->CreateIntConst(k8BitSize, PTY_i32)); - } - - pIdxS = GetCurrentFunc()->GetPregTab()->CreatePreg(PTY_u64); - StmtNode *sStmp = mirBuilder->CreateStmtRegassign(PTY_u64, pIdxS, shift); +// struct passed in fpregs, lowered into +// call &foo +// regassign f64 %1 (regread f64 %%retval0) +// regassign ptr %2 (addrof ptr $s) +// iassign <* f64> 0 (regread ptr %2, regread f64 %1) +void CGLowerer::LowerStructReturnInFpRegs(BlockNode &newBlk, const StmtNode &stmt, const MIRSymbol &symbol, + PrimType primType, size_t elemNum) +{ + // save retvals + static constexpr std::array sregs = {kSregRetval0, kSregRetval1, kSregRetval2, kSregRetval3}; + std::vector pIdxs(sregs.size(), 0); + for (uint32 i = 0; i < elemNum; ++i) { + auto *regreadNode = mirBuilder->CreateExprRegread(primType, -sregs[i]); + pIdxs[i] = GetCurrentFunc()->GetPregTab()->CreatePreg(primType); + auto *aStmt = mirBuilder->CreateStmtRegassign(primType, pIdxs[i], regreadNode); + newBlk.AddStatement(aStmt); + } - pIdx1R = pIdx2R = pIdxS; - newBlk.AddStatement(sStmp); - size -= k1ByteSize; - curSize += k1ByteSize; - } - newBlk.AddStatement(aStmt); + // save &s + BaseNode *regAddr = mirBuilder->CreateExprAddrof(0, symbol); + LowerTypePtr(*regAddr); + PregIdx pIdxL = GetCurrentFunc()->GetPregTab()->CreatePreg(GetLoweredPtrType()); + auto *aStmt = mirBuilder->CreateStmtRegassign(PTY_a64, pIdxL, regAddr); + newBlk.AddStatement(aStmt); + + // str retvals to &s + for (uint32 i = 0; i < elemNum; ++i) { + uint32 offsetSize = i * GetPrimTypeSize(primType); + BaseNode *addrNode = mirBuilder->CreateExprRegread(GetLoweredPtrType(), pIdxL); + // addr add offset + if (offsetSize != 0) { + MIRType *addrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetLoweredPtrType()); + addrNode = mirBuilder->CreateExprBinary(OP_add, *addrType, addrNode, + mirBuilder->CreateIntConst(offsetSize, PTY_i32)); } + // gen iassigen to addr + auto *pointedType = GlobalTables::GetTypeTable().GetPrimType(primType); + auto *iassignStmt = mirBuilder->CreateStmtIassign(*beCommon.BeGetOrCreatePointerType(*pointedType), 0, addrNode, + mirBuilder->CreateExprRegread(PTY_u64, pIdxs[i])); + newBlk.AddStatement(iassignStmt); } - nextStmt = nextStmt->GetNext(); // skip the dassign - return true; } void CGLowerer::LowerStmt(StmtNode &stmt, BlockNode &newBlk) @@ -1924,7 +1855,7 @@ BlockNode *CGLowerer::LowerBlock(BlockNode &block) // pass the addr of lvar if this is a struct call assignment bool lvar = false; // nextStmt could be changed by the call to LowerStructReturn - if (!LowerStructReturn(*newBlk, stmt, nextStmt, lvar, &block)) { + if (!LowerStructReturn(*newBlk, *stmt, lvar)) { newBlk->AppendStatementsFromBlock(*LowerCallAssignedStmt(*stmt, lvar)); } break; @@ -2260,19 +2191,38 @@ StmtNode *CGLowerer::LowerCall(CallNode &callNode, StmtNode *&nextStmt, BlockNod return &callNode; } +void CGLowerer::LowerTypePtr(BaseNode &node) const +{ + if ((node.GetPrimType() == PTY_ptr) || (node.GetPrimType() == PTY_ref)) { + node.SetPrimType(GetLoweredPtrType()); + } + + if (kOpcodeInfo.IsTypeCvt(node.GetOpCode())) { + auto &cvt = static_cast(node); + if ((cvt.FromType() == PTY_ptr) || (cvt.FromType() == PTY_ref)) { + cvt.SetFromType(GetLoweredPtrType()); + } + } else if (kOpcodeInfo.IsCompare(node.GetOpCode())) { + auto &cmp = static_cast(node); + if ((cmp.GetOpndType() == PTY_ptr) || (cmp.GetOpndType() == PTY_ref)) { + cmp.SetOpndType(GetLoweredPtrType()); + } + } +} + void CGLowerer::LowerEntry(MIRFunction &func) { // determine if needed to insert fake parameter to return struct for current function if (func.IsReturnStruct()) { MIRType *retType = func.GetReturnType(); #if TARGAARCH64 - if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) { - PrimType pty = IsStructElementSame(retType); - if (pty == PTY_f32 || pty == PTY_f64 || IsPrimitiveVector(pty)) { - func.SetStructReturnedInRegs(); - return; + if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) { + PrimType pty = IsStructElementSame(retType); + if (pty == PTY_f32 || pty == PTY_f64 || IsPrimitiveVector(pty)) { + func.SetStructReturnedInRegs(); + return; + } } - } #endif if (retType->GetPrimType() != PTY_agg) { return; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp index 1d7ab897237bd4c7a3e27579b488d37531c8f41d..75fd0ede9c05bb37d9531e651dd9f5085aa84b39 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp @@ -20,6 +20,11 @@ namespace maplebe { using namespace maple; namespace AArch64Abi { +std::vector intReturnRegs = {R0, R1, R2, R3, R4, R5, R6, R7}; +std::vector floatReturnRegs = {V0, V1, V2, V3, V4, V5, V6, V7}; +std::vector intParmRegs = {R0, R1, R2, R3, R4, R5, R6, R7}; +std::vector floatParmRegs = {V0, V1, V2, V3, V4, V5, V6, V7}; + bool IsAvailableReg(AArch64reg reg) { switch (reg) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_args.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_args.cpp index 5c10c2c49492c0ea4be539287c3f875aa1e46062..f2c9a986ac58347bb121c7165835e1252efd2f89 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_args.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_args.cpp @@ -23,436 +23,206 @@ using namespace maple; void AArch64MoveRegArgs::Run() { + BB *formerCurBB = aarFunc->GetCurBB(); MoveVRegisterArgs(); MoveRegisterArgs(); + aarFunc->SetCurBB(*formerCurBB); } -void AArch64MoveRegArgs::CollectRegisterArgs(std::map &argsList, std::vector &indexList, - std::map &pairReg, std::vector &numFpRegs, - std::vector &fpSize) const +void AArch64MoveRegArgs::MoveRegisterArgs() const { - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - uint32 numFormal = static_cast(aarchCGFunc->GetFunction().GetFormalCount()); - numFpRegs.resize(numFormal); - fpSize.resize(numFormal); - CCImpl &parmlocator = *static_cast(cgFunc)->GetOrCreateLocator(cgFunc->GetCurCallConvKind()); + aarFunc->GetDummyBB()->ClearInsns(); + aarFunc->SetCurBB(*aarFunc->GetDummyBB()); + + auto &mirFunc = aarFunc->GetFunction(); + CCImpl &parmlocator = + *static_cast(cgFunc)->GetOrCreateLocator(CCImpl::GetCallConvKind(cgFunc->GetFunction())); CCLocInfo ploc; - uint32 start = 0; - if (numFormal) { - MIRFunction *func = const_cast(aarchCGFunc->GetBecommon().GetMIRModule().CurFunction()); - if (func->IsReturnStruct() && func->IsFirstArgReturn()) { - TyIdx tyIdx = func->GetFuncRetStructTyIdx(); - if (aarchCGFunc->GetBecommon().GetTypeSize(tyIdx) <= k16ByteSize) { - start = 1; - } - } - } - for (uint32 i = start; i < numFormal; ++i) { - MIRType *ty = aarchCGFunc->GetFunction().GetNthParamType(i); - parmlocator.LocateNextParm(*ty, ploc, i == 0, &aarchCGFunc->GetFunction()); + for (uint32 i = 0; i < mirFunc.GetFormalCount(); ++i) { + MIRType *ty = mirFunc.GetNthParamType(i); + parmlocator.LocateNextParm(*ty, ploc, i == 0, mirFunc.GetMIRFuncType()); if (ploc.reg0 == kRinvalid) { continue; } - AArch64reg reg0 = static_cast(ploc.reg0); - MIRSymbol *sym = aarchCGFunc->GetFunction().GetFormal(i); + auto *sym = mirFunc.GetFormal(i); if (sym->IsPreg()) { continue; } - argsList[i] = reg0; - indexList.emplace_back(i); - if (ploc.reg1 == kRinvalid) { - continue; - } - if (ploc.numFpPureRegs) { - uint32 index = i; - numFpRegs[index] = ploc.numFpPureRegs; - fpSize[index] = ploc.fpSize; - continue; - } - pairReg[i] = static_cast(ploc.reg1); - } -} - -AArch64ArgInfo AArch64MoveRegArgs::GetArgInfo(std::map &argsList, std::vector &numFpRegs, - std::vector &fpSize, uint32 argIndex) const -{ - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - AArch64ArgInfo argInfo; - argInfo.reg = argsList[argIndex]; - argInfo.mirTy = aarchCGFunc->GetFunction().GetNthParamType(argIndex); - argInfo.symSize = aarchCGFunc->GetBecommon().GetTypeSize(argInfo.mirTy->GetTypeIndex()); - argInfo.memPairSecondRegSize = 0; - argInfo.doMemPairOpt = false; - argInfo.createTwoStores = false; - argInfo.isTwoRegParm = false; - - if (GetVecLanes(argInfo.mirTy->GetPrimType()) > 0) { - /* vector type */ - argInfo.stkSize = argInfo.symSize; - } else if ((argInfo.symSize > k8ByteSize) && (argInfo.symSize <= k16ByteSize)) { - argInfo.isTwoRegParm = true; - if (numFpRegs[argIndex] > kOneRegister) { - argInfo.symSize = argInfo.stkSize = fpSize[argIndex]; - } else { - if (argInfo.symSize > k12ByteSize) { - argInfo.memPairSecondRegSize = k8ByteSize; - } else { - /* Round to 4 the stack space required for storing the struct */ - argInfo.memPairSecondRegSize = k4ByteSize; + auto *symLoc = aarFunc->GetMemlayout()->GetSymAllocInfo(sym->GetStIndex()); + auto *baseOpnd = aarFunc->GetBaseReg(*symLoc); + auto offset = aarFunc->GetBaseOffset(*symLoc); + auto generateStrInsn = [this, baseOpnd, &offset, sym, symLoc](AArch64reg reg, PrimType primType) { + RegOperand ®Opnd = aarFunc->GetOrCreatePhysicalRegisterOperand(reg, GetPrimTypeBitSize(primType), + aarFunc->GetRegTyFromPrimTy(primType)); + OfstOperand &ofstOpnd = + aarFunc->CreateOfstOpnd(static_cast(static_cast(offset)), k32BitSize); + AArch64MemLayout *memLayout = static_cast(aarFunc->GetMemlayout()); + if (memLayout->IsSegMentVaried(symLoc->GetMemSegment())) { + ofstOpnd.SetVary(kUnAdjustVary); } - argInfo.doMemPairOpt = true; - if (CGOptions::IsArm64ilp32()) { - argInfo.symSize = argInfo.stkSize = k8ByteSize; - } else { - argInfo.symSize = argInfo.stkSize = GetPointerSize(); + auto *memOpnd = aarFunc->CreateMemOperand(GetPrimTypeBitSize(primType), *baseOpnd, ofstOpnd, false); + + MOperator mOp = aarFunc->PickStInsn(GetPrimTypeBitSize(primType), primType); + Insn &insn = aarFunc->GetInsnBuilder()->BuildInsn(mOp, regOpnd, *memOpnd); + if (aarFunc->GetCG()->GenerateVerboseCG()) { + insn.SetComment(std::string("store param: ").append(sym->GetName())); } + aarFunc->GetCurBB()->AppendInsn(insn); + offset += static_cast(GetPrimTypeSize(primType)); + }; + generateStrInsn(static_cast(ploc.GetReg0()), ploc.GetPrimTypeOfReg0()); + if (ploc.GetReg1() != kRinvalid) { + generateStrInsn(static_cast(ploc.GetReg1()), ploc.GetPrimTypeOfReg1()); } - } else if (argInfo.symSize > k16ByteSize) { - /* For large struct passing, a pointer to the copy is used. */ - if (CGOptions::IsArm64ilp32()) { - argInfo.symSize = argInfo.stkSize = k8ByteSize; - } else { - argInfo.symSize = argInfo.stkSize = GetPointerSize(); + if (ploc.GetReg2() != kRinvalid) { + generateStrInsn(static_cast(ploc.GetReg2()), ploc.GetPrimTypeOfReg2()); } - } else if ((argInfo.mirTy->GetPrimType() == PTY_agg) && (argInfo.symSize < k8ByteSize)) { - /* - * For small aggregate parameter, set to minimum of 8 bytes. - * B.5:If the argument type is a Composite Type then the size of the argument is rounded up to the - * nearest multiple of 8 bytes. - */ - argInfo.symSize = argInfo.stkSize = k8ByteSize; - } else if (numFpRegs[argIndex] > kOneRegister) { - argInfo.isTwoRegParm = true; - argInfo.symSize = argInfo.stkSize = fpSize[argIndex]; - } else { - argInfo.stkSize = (argInfo.symSize < k4ByteSize) ? k4ByteSize : argInfo.symSize; - if (argInfo.symSize > k4ByteSize) { - argInfo.symSize = k8ByteSize; + if (ploc.GetReg3() != kRinvalid) { + generateStrInsn(static_cast(ploc.GetReg3()), ploc.GetPrimTypeOfReg3()); } } - argInfo.regType = (argInfo.reg < V0) ? kRegTyInt : kRegTyFloat; - argInfo.sym = aarchCGFunc->GetFunction().GetFormal(argIndex); - CHECK_NULL_FATAL(argInfo.sym); - argInfo.symLoc = static_cast( - aarchCGFunc->GetMemlayout()->GetSymAllocInfo(argInfo.sym->GetStIndex())); - CHECK_NULL_FATAL(argInfo.symLoc); - if (argInfo.doMemPairOpt && (aarchCGFunc->GetBaseOffset(*(argInfo.symLoc)) & 0x7)) { - /* Do not optimize for struct reg pair for unaligned access. - * However, this symbol requires two parameter registers, separate stores must be generated. - */ - argInfo.symSize = GetPointerSize(); - argInfo.doMemPairOpt = false; - argInfo.createTwoStores = true; - } - return argInfo; -} -bool AArch64MoveRegArgs::IsInSameSegment(const AArch64ArgInfo &firstArgInfo, const AArch64ArgInfo &secondArgInfo) const -{ - if (firstArgInfo.symLoc->GetMemSegment() != secondArgInfo.symLoc->GetMemSegment()) { - return false; - } - if (firstArgInfo.symSize != secondArgInfo.symSize) { - return false; - } - if (firstArgInfo.symSize != k4ByteSize && firstArgInfo.symSize != k8ByteSize) { - return false; - } - if (firstArgInfo.regType != secondArgInfo.regType) { - return false; - } - return firstArgInfo.symLoc->GetOffset() + firstArgInfo.stkSize == secondArgInfo.symLoc->GetOffset(); -} - -void AArch64MoveRegArgs::GenerateStpInsn(const AArch64ArgInfo &firstArgInfo, const AArch64ArgInfo &secondArgInfo) -{ - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - RegOperand *baseOpnd = static_cast(aarchCGFunc->GetBaseReg(*firstArgInfo.symLoc)); - RegOperand ®Opnd = aarchCGFunc->GetOrCreatePhysicalRegisterOperand( - firstArgInfo.reg, firstArgInfo.stkSize * kBitsPerByte, firstArgInfo.regType); - MOperator mOp = firstArgInfo.regType == kRegTyInt ? ((firstArgInfo.stkSize > k4ByteSize) ? MOP_xstp : MOP_wstp) - : ((firstArgInfo.stkSize > k4ByteSize) ? MOP_dstp : MOP_sstp); - RegOperand *regOpnd2 = &aarchCGFunc->GetOrCreatePhysicalRegisterOperand( - secondArgInfo.reg, firstArgInfo.stkSize * kBitsPerByte, firstArgInfo.regType); - if (firstArgInfo.doMemPairOpt && firstArgInfo.isTwoRegParm) { - AArch64reg regFp2 = static_cast(firstArgInfo.reg + kOneRegister); - regOpnd2 = &aarchCGFunc->GetOrCreatePhysicalRegisterOperand(regFp2, firstArgInfo.stkSize * kBitsPerByte, - firstArgInfo.regType); - } - - int32 limit = (secondArgInfo.stkSize > k4ByteSize) ? kStpLdpImm64UpperBound : kStpLdpImm32UpperBound; - int32 stOffset = aarchCGFunc->GetBaseOffset(*firstArgInfo.symLoc); - MemOperand *memOpnd = nullptr; - if (stOffset > limit || baseReg != nullptr) { - if (baseReg == nullptr || lastSegment != firstArgInfo.symLoc->GetMemSegment()) { - ImmOperand &immOpnd = - aarchCGFunc->CreateImmOperand(stOffset - firstArgInfo.symLoc->GetOffset(), k64BitSize, false); - baseReg = &aarchCGFunc->CreateRegisterOperandOfType(kRegTyInt, k8ByteSize); - lastSegment = firstArgInfo.symLoc->GetMemSegment(); - aarchCGFunc->SelectAdd(*baseReg, *baseOpnd, immOpnd, GetLoweredPtrType()); - } - OfstOperand &offsetOpnd = - aarchCGFunc->CreateOfstOpnd(static_cast(firstArgInfo.symLoc->GetOffset()), k32BitSize); - if (firstArgInfo.symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) { - offsetOpnd.SetVary(kUnAdjustVary); - } - memOpnd = aarchCGFunc->CreateMemOperand(MemOperand::kAddrModeBOi, firstArgInfo.stkSize * kBitsPerByte, *baseReg, - nullptr, &offsetOpnd, firstArgInfo.sym); + if (cgFunc->GetCG()->IsLmbc() && (cgFunc->GetSpSaveReg() != 0)) { + /* lmbc uses vreg act as SP when alloca is present due to usage of FP for - offset */ + aarFunc->GetFirstBB()->InsertAtEnd(*aarFunc->GetDummyBB()); } else { - OfstOperand &offsetOpnd = - aarchCGFunc->CreateOfstOpnd(static_cast(static_cast(stOffset)), k32BitSize); - if (firstArgInfo.symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) { - offsetOpnd.SetVary(kUnAdjustVary); - } - memOpnd = aarchCGFunc->CreateMemOperand(MemOperand::kAddrModeBOi, firstArgInfo.stkSize * kBitsPerByte, - *baseOpnd, nullptr, &offsetOpnd, firstArgInfo.sym); - } - Insn &pushInsn = aarchCGFunc->GetInsnBuilder()->BuildInsn(mOp, regOpnd, *regOpnd2, *memOpnd); - if (aarchCGFunc->GetCG()->GenerateVerboseCG()) { - std::string argName = firstArgInfo.sym->GetName() + " " + secondArgInfo.sym->GetName(); - pushInsn.SetComment(std::string("store param: ").append(argName)); - } - aarchCGFunc->GetCurBB()->AppendInsn(pushInsn); -} - -void AArch64MoveRegArgs::GenOneInsn(const AArch64ArgInfo &argInfo, RegOperand &baseOpnd, - uint32 stBitSize, AArch64reg dest, - int32 offset) const -{ - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - MOperator mOp = aarchCGFunc->PickStInsn(stBitSize, argInfo.mirTy->GetPrimType()); - RegOperand ®Opnd = aarchCGFunc->GetOrCreatePhysicalRegisterOperand(dest, stBitSize, argInfo.regType); - - OfstOperand &offsetOpnd = aarchCGFunc->CreateOfstOpnd(static_cast(static_cast(offset)), k32BitSize); - if (argInfo.symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) { - offsetOpnd.SetVary(kUnAdjustVary); - } - MemOperand *memOpnd = - aarchCGFunc->CreateMemOperand(MemOperand::kAddrModeBOi, stBitSize, baseOpnd, nullptr, &offsetOpnd, argInfo.sym); - Insn &insn = aarchCGFunc->GetInsnBuilder()->BuildInsn(mOp, regOpnd, *memOpnd); - if (aarchCGFunc->GetCG()->GenerateVerboseCG()) { - insn.SetComment(std::string("store param: ").append(argInfo.sym->GetName())); + /* Java requires insertion at begining as it has fast unwind and other features */ + aarFunc->GetFirstBB()->InsertAtBeginning(*aarFunc->GetDummyBB()); } - aarchCGFunc->GetCurBB()->AppendInsn(insn); -} - -void AArch64MoveRegArgs::GenerateStrInsn(const AArch64ArgInfo &argInfo, - AArch64reg reg2, uint32 numFpRegs, uint32 fpSize) -{ - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - int32 stOffset = aarchCGFunc->GetBaseOffset(*argInfo.symLoc); - RegOperand *baseOpnd = static_cast(aarchCGFunc->GetBaseReg(*argInfo.symLoc)); - RegOperand ®Opnd = - aarchCGFunc->GetOrCreatePhysicalRegisterOperand(argInfo.reg, argInfo.stkSize * kBitsPerByte, argInfo.regType); - MemOperand *memOpnd = nullptr; - if (MemOperand::IsPIMMOffsetOutOfRange(stOffset, argInfo.symSize * kBitsPerByte) || - (baseReg != nullptr && (lastSegment == argInfo.symLoc->GetMemSegment()))) { - if (baseReg == nullptr || lastSegment != argInfo.symLoc->GetMemSegment()) { - ImmOperand &immOpnd = - aarchCGFunc->CreateImmOperand(stOffset - argInfo.symLoc->GetOffset(), k64BitSize, false); - baseReg = &aarchCGFunc->CreateRegisterOperandOfType(kRegTyInt, k8ByteSize); - lastSegment = argInfo.symLoc->GetMemSegment(); - aarchCGFunc->SelectAdd(*baseReg, *baseOpnd, immOpnd, PTY_a64); - } - OfstOperand &offsetOpnd = - aarchCGFunc->CreateOfstOpnd(static_cast(argInfo.symLoc->GetOffset()), k32BitSize); - if (argInfo.symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) { - offsetOpnd.SetVary(kUnAdjustVary); - } - memOpnd = aarchCGFunc->CreateMemOperand(MemOperand::kAddrModeBOi, argInfo.symSize * kBitsPerByte, *baseReg, - nullptr, &offsetOpnd, argInfo.sym); - } else { - OfstOperand &offsetOpnd = - aarchCGFunc->CreateOfstOpnd(static_cast(static_cast(stOffset)), k32BitSize); - if (argInfo.symLoc->GetMemSegment()->GetMemSegmentKind() == kMsArgsStkPassed) { - offsetOpnd.SetVary(kUnAdjustVary); - } - memOpnd = aarchCGFunc->CreateMemOperand(MemOperand::kAddrModeBOi, argInfo.symSize * kBitsPerByte, *baseOpnd, - nullptr, &offsetOpnd, argInfo.sym); - } - - MOperator mOp = aarchCGFunc->PickStInsn(argInfo.symSize * kBitsPerByte, argInfo.mirTy->GetPrimType()); - Insn &insn = aarchCGFunc->GetInsnBuilder()->BuildInsn(mOp, regOpnd, *memOpnd); - if (aarchCGFunc->GetCG()->GenerateVerboseCG()) { - insn.SetComment(std::string("store param: ").append(argInfo.sym->GetName())); - } - aarchCGFunc->GetCurBB()->AppendInsn(insn); - - if (argInfo.createTwoStores || argInfo.doMemPairOpt) { - /* second half of the struct passing by registers. */ - uint32 part2BitSize = argInfo.memPairSecondRegSize * kBitsPerByte; - GenOneInsn(argInfo, *baseOpnd, part2BitSize, reg2, (stOffset + GetPointerSize())); - } else if (numFpRegs > kOneRegister) { - uint32 fpSizeBits = fpSize * kBitsPerByte; - AArch64reg regFp2 = static_cast(argInfo.reg + kOneRegister); - GenOneInsn(argInfo, *baseOpnd, fpSizeBits, regFp2, (stOffset + static_cast(fpSize))); - if (numFpRegs > kTwoRegister) { - AArch64reg regFp3 = static_cast(argInfo.reg + kTwoRegister); - GenOneInsn(argInfo, *baseOpnd, fpSizeBits, regFp3, (stOffset + static_cast(fpSize * k4BitShift))); - } - if (numFpRegs > kThreeRegister) { - AArch64reg regFp3 = static_cast(argInfo.reg + kThreeRegister); - GenOneInsn(argInfo, *baseOpnd, fpSizeBits, regFp3, (stOffset + static_cast(fpSize * k8BitShift))); - } - } -} - -void AArch64MoveRegArgs::MoveRegisterArgs() -{ - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - BB *formerCurBB = aarchCGFunc->GetCurBB(); - aarchCGFunc->GetDummyBB()->ClearInsns(); - aarchCGFunc->SetCurBB(*aarchCGFunc->GetDummyBB()); - - std::map movePara; - std::vector moveParaIndex; - std::map pairReg; - std::vector numFpRegs; - std::vector fpSize; - CollectRegisterArgs(movePara, moveParaIndex, pairReg, numFpRegs, fpSize); - - std::vector::iterator it; - std::vector::iterator next; - for (it = moveParaIndex.begin(); it != moveParaIndex.end(); ++it) { - uint32 firstIndex = *it; - AArch64ArgInfo firstArgInfo = GetArgInfo(movePara, numFpRegs, fpSize, firstIndex); - next = it; - ++next; - if ((next != moveParaIndex.end()) || (firstArgInfo.doMemPairOpt)) { - uint32 secondIndex = (firstArgInfo.doMemPairOpt) ? firstIndex : *next; - AArch64ArgInfo secondArgInfo = GetArgInfo(movePara, numFpRegs, fpSize, secondIndex); - secondArgInfo.reg = (firstArgInfo.doMemPairOpt) ? pairReg[firstIndex] : movePara[secondIndex]; - secondArgInfo.symSize = - (firstArgInfo.doMemPairOpt) ? firstArgInfo.memPairSecondRegSize : secondArgInfo.symSize; - secondArgInfo.symLoc = (firstArgInfo.doMemPairOpt) - ? secondArgInfo.symLoc - : static_cast(aarchCGFunc->GetMemlayout()->GetSymAllocInfo( - secondArgInfo.sym->GetStIndex())); - /* Make sure they are in same segment if want to use stp */ - if (((firstArgInfo.isTwoRegParm && secondArgInfo.isTwoRegParm) || - (!firstArgInfo.isTwoRegParm && !secondArgInfo.isTwoRegParm)) && - (firstArgInfo.doMemPairOpt || IsInSameSegment(firstArgInfo, secondArgInfo))) { - GenerateStpInsn(firstArgInfo, secondArgInfo); - if (!firstArgInfo.doMemPairOpt) { - it = next; - } - continue; - } - } - GenerateStrInsn(firstArgInfo, pairReg[firstIndex], numFpRegs[firstIndex], fpSize[firstIndex]); - } - - aarchCGFunc->GetFirstBB()->InsertAtBeginning(*aarchCGFunc->GetDummyBB()); - aarchCGFunc->SetCurBB(*formerCurBB); } void AArch64MoveRegArgs::MoveLocalRefVarToRefLocals(MIRSymbol &mirSym) const { - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); + AArch64CGFunc *aarFunc = static_cast(cgFunc); PrimType stype = mirSym.GetType()->GetPrimType(); uint32 byteSize = GetPrimTypeSize(stype); uint32 bitSize = byteSize * kBitsPerByte; - MemOperand &memOpnd = aarchCGFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, true); + MemOperand &memOpnd = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, true); RegOperand *regOpnd = nullptr; if (mirSym.IsPreg()) { - PregIdx pregIdx = aarchCGFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(mirSym.GetPreg()->GetPregNo()); - regOpnd = - &aarchCGFunc->GetOrCreateVirtualRegisterOperand(aarchCGFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); + PregIdx pregIdx = aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno( + static_cast(mirSym.GetPreg()->GetPregNo())); + regOpnd = &aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); } else { - regOpnd = &aarchCGFunc->GetOrCreateVirtualRegisterOperand(aarchCGFunc->NewVReg(kRegTyInt, k8ByteSize)); - } - Insn &insn = aarchCGFunc->GetInsnBuilder()->BuildInsn(aarchCGFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), - *regOpnd, memOpnd); - MemOperand &memOpnd1 = aarchCGFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, false); - Insn &insn1 = aarchCGFunc->GetInsnBuilder()->BuildInsn(aarchCGFunc->PickStInsn(GetPrimTypeBitSize(stype), stype), - *regOpnd, memOpnd1); - aarchCGFunc->GetCurBB()->InsertInsnBegin(insn1); - aarchCGFunc->GetCurBB()->InsertInsnBegin(insn); + regOpnd = &aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->NewVReg(kRegTyInt, k8ByteSize)); + } + Insn &insn = + aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), *regOpnd, memOpnd); + MemOperand &memOpnd1 = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize, false); + Insn &insn1 = + aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickStInsn(GetPrimTypeBitSize(stype), stype), *regOpnd, memOpnd1); + aarFunc->GetCurBB()->InsertInsnBegin(insn1); + aarFunc->GetCurBB()->InsertInsnBegin(insn); } void AArch64MoveRegArgs::LoadStackArgsToVReg(MIRSymbol &mirSym) const { - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); + AArch64CGFunc *aarFunc = static_cast(cgFunc); PrimType stype = mirSym.GetType()->GetPrimType(); uint32 byteSize = GetPrimTypeSize(stype); uint32 bitSize = byteSize * kBitsPerByte; - MemOperand &memOpnd = aarchCGFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize); - PregIdx pregIdx = aarchCGFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(mirSym.GetPreg()->GetPregNo()); + MemOperand &memOpnd = aarFunc->GetOrCreateMemOpnd(mirSym, 0, bitSize); + PregIdx pregIdx = + aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(static_cast(mirSym.GetPreg()->GetPregNo())); RegOperand &dstRegOpnd = - aarchCGFunc->GetOrCreateVirtualRegisterOperand(aarchCGFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); - Insn &insn = aarchCGFunc->GetInsnBuilder()->BuildInsn(aarchCGFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), - dstRegOpnd, memOpnd); + aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); + Insn &insn = aarFunc->GetInsnBuilder()->BuildInsn(aarFunc->PickLdInsn(GetPrimTypeBitSize(stype), stype), dstRegOpnd, + memOpnd); - if (aarchCGFunc->GetCG()->GenerateVerboseCG()) { + if (aarFunc->GetCG()->GenerateVerboseCG()) { std::string key = "param: %%"; key += std::to_string(mirSym.GetPreg()->GetPregNo()); DEBUG_ASSERT(mirSym.GetStorageClass() == kScFormal, "vreg parameters should be kScFormal type."); insn.SetComment(key); } - aarchCGFunc->GetCurBB()->InsertInsnBegin(insn); + aarFunc->GetCurBB()->InsertInsnBegin(insn); } void AArch64MoveRegArgs::MoveArgsToVReg(const CCLocInfo &ploc, MIRSymbol &mirSym) const { - auto *aarchCGFunc = static_cast(cgFunc); + // when args parameter type i128, reg1 will be used. + // but, i128 is not supported in back-end + CHECK_FATAL(ploc.reg2 == kRinvalid, "NIY"); RegType regType = (ploc.reg0 < V0) ? kRegTyInt : kRegTyFloat; - PrimType stype = mirSym.GetType()->GetPrimType(); - uint32 byteSize = GetPrimTypeSize(stype); + PrimType sType = mirSym.GetType()->GetPrimType(); + uint32 byteSize = GetPrimTypeSize(sType); uint32 srcBitSize = ((byteSize < k4ByteSize) ? k4ByteSize : byteSize) * kBitsPerByte; - PregIdx pregIdx = aarchCGFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(mirSym.GetPreg()->GetPregNo()); + PregIdx pregIdx = + aarFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(static_cast(mirSym.GetPreg()->GetPregNo())); RegOperand &dstRegOpnd = - aarchCGFunc->GetOrCreateVirtualRegisterOperand(aarchCGFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); + aarFunc->GetOrCreateVirtualRegisterOperand(aarFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx)); dstRegOpnd.SetSize(srcBitSize); RegOperand &srcRegOpnd = - aarchCGFunc->GetOrCreatePhysicalRegisterOperand(static_cast(ploc.reg0), srcBitSize, regType); + aarFunc->GetOrCreatePhysicalRegisterOperand(static_cast(ploc.reg0), srcBitSize, regType); DEBUG_ASSERT(mirSym.GetStorageClass() == kScFormal, "should be args"); - MOperator mOp = aarchCGFunc->PickMovBetweenRegs(stype, stype); + MOperator mOp = aarFunc->PickMovBetweenRegs(sType, sType); if (mOp == MOP_vmovvv || mOp == MOP_vmovuu) { - VectorInsn &vInsn = aarchCGFunc->GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]); - vInsn.AddOpndChain(dstRegOpnd).AddOpndChain(srcRegOpnd); - auto *vecSpec1 = aarchCGFunc->GetMemoryPool()->New(srcBitSize >> k3ByteSize, k8BitSize); - auto *vecSpec2 = aarchCGFunc->GetMemoryPool()->New(srcBitSize >> k3ByteSize, k8BitSize); - vInsn.PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2); - aarchCGFunc->GetCurBB()->InsertInsnBegin(vInsn); + auto &vInsn = aarFunc->GetInsnBuilder()->BuildVectorInsn(mOp, AArch64CG::kMd[mOp]); + (void)vInsn.AddOpndChain(dstRegOpnd).AddOpndChain(srcRegOpnd); + auto *vecSpec1 = aarFunc->GetMemoryPool()->New(srcBitSize >> k3ByteSize, k8BitSize); + auto *vecSpec2 = aarFunc->GetMemoryPool()->New(srcBitSize >> k3ByteSize, k8BitSize); + (void)vInsn.PushRegSpecEntry(vecSpec1).PushRegSpecEntry(vecSpec2); + aarFunc->GetCurBB()->InsertInsnBegin(vInsn); return; } - Insn &insn = aarchCGFunc->GetInsnBuilder()->BuildInsn(mOp, dstRegOpnd, srcRegOpnd); - if (aarchCGFunc->GetCG()->GenerateVerboseCG()) { - std::string key = "param: %%"; - key += std::to_string(mirSym.GetPreg()->GetPregNo()); - insn.SetComment(key); + Insn &insn = CreateMoveArgsToVRegInsn(mOp, dstRegOpnd, srcRegOpnd, sType); + if (aarFunc->GetCG()->GenerateVerboseCG()) { + std::string str = "param: %%"; + str += std::to_string(mirSym.GetPreg()->GetPregNo()); + insn.SetComment(str); } - aarchCGFunc->GetCurBB()->InsertInsnBegin(insn); + aarFunc->GetCurBB()->InsertInsnBegin(insn); } -void AArch64MoveRegArgs::MoveVRegisterArgs() +Insn &AArch64MoveRegArgs::CreateMoveArgsToVRegInsn(MOperator mOp, RegOperand &destOpnd, RegOperand &srcOpnd, + PrimType primType) const { - AArch64CGFunc *aarchCGFunc = static_cast(cgFunc); - BB *formerCurBB = aarchCGFunc->GetCurBB(); - aarchCGFunc->GetDummyBB()->ClearInsns(); - aarchCGFunc->SetCurBB(*aarchCGFunc->GetDummyBB()); - CCImpl &parmlocator = *static_cast(cgFunc)->GetOrCreateLocator(cgFunc->GetCurCallConvKind()); - CCLocInfo ploc; - - uint32 formalCount = static_cast(aarchCGFunc->GetFunction().GetFormalCount()); - uint32 start = 0; - if (formalCount) { - MIRFunction *func = const_cast(aarchCGFunc->GetBecommon().GetMIRModule().CurFunction()); - if (func->IsReturnStruct() && func->IsFirstArgReturn()) { - TyIdx tyIdx = func->GetFuncRetStructTyIdx(); - if (aarchCGFunc->GetBecommon().GetTypeSize(tyIdx) <= k16BitSize) { - start = 1; + if (mOp == MOP_wmovrr || mOp == MOP_xmovrr) { + /* callee ensure the validbit of parameters of function */ + switch (primType) { + case PTY_u1: { + ImmOperand &lsbOpnd = aarFunc->CreateImmOperand(maplebe::k0BitSize, srcOpnd.GetSize(), false); + ImmOperand &widthOpnd = aarFunc->CreateImmOperand(maplebe::k1BitSize, srcOpnd.GetSize(), false); + bool is64Bit = (srcOpnd.GetSize() == maplebe::k64BitSize); + return aarFunc->GetInsnBuilder()->BuildInsn(is64Bit ? MOP_xubfxrri6i6 : MOP_wubfxrri5i5, destOpnd, + srcOpnd, lsbOpnd, widthOpnd); } + case PTY_u8: + case PTY_i8: + return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxtb32, destOpnd, srcOpnd); + case PTY_u16: + case PTY_i16: + return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxth32, destOpnd, srcOpnd); + case PTY_u32: + case PTY_i32: { + destOpnd.SetValidBitsNum(maplebe::k64BitSize); + return aarFunc->GetInsnBuilder()->BuildInsn(MOP_xuxtw64, destOpnd, srcOpnd); + } + default: + return aarFunc->GetInsnBuilder()->BuildInsn(mOp, destOpnd, srcOpnd); } + } else { + return aarFunc->GetInsnBuilder()->BuildInsn(mOp, destOpnd, srcOpnd); } - for (uint32 i = start; i < formalCount; ++i) { - MIRType *ty = aarchCGFunc->GetFunction().GetNthParamType(i); - parmlocator.LocateNextParm(*ty, ploc, i == 0, &aarchCGFunc->GetFunction()); - MIRSymbol *sym = aarchCGFunc->GetFunction().GetFormal(i); +} + +void AArch64MoveRegArgs::MoveVRegisterArgs() +{ + aarFunc->GetDummyBB()->ClearInsns(); + aarFunc->SetCurBB(*aarFunc->GetDummyBB()); + CCImpl &parmlocator = + *static_cast(cgFunc)->GetOrCreateLocator(CCImpl::GetCallConvKind(cgFunc->GetFunction())); + CCLocInfo ploc; + + auto &mirFunc = aarFunc->GetFunction(); + for (size_t i = 0; i < mirFunc.GetFormalCount(); ++i) { + MIRType *ty = mirFunc.GetNthParamType(i); + parmlocator.LocateNextParm(*ty, ploc, (i == 0), mirFunc.GetMIRFuncType()); + MIRSymbol *sym = mirFunc.GetFormal(i); /* load locarefvar formals to store in the reflocals. */ - if (aarchCGFunc->GetFunction().GetNthParamAttr(i).GetAttr(ATTR_localrefvar) && ploc.reg0 == kRinvalid) { + if (mirFunc.GetNthParamAttr(i).GetAttr(ATTR_localrefvar) && ploc.reg0 == kRinvalid) { MoveLocalRefVarToRefLocals(*sym); } @@ -468,7 +238,12 @@ void AArch64MoveRegArgs::MoveVRegisterArgs() } } - aarchCGFunc->GetFirstBB()->InsertAtBeginning(*aarchCGFunc->GetDummyBB()); - aarchCGFunc->SetCurBB(*formerCurBB); + if (cgFunc->GetCG()->IsLmbc() && (cgFunc->GetSpSaveReg() != 0)) { + /* lmbc uses vreg act as SP when alloca is present due to usage of FP for - offset */ + aarFunc->GetFirstBB()->InsertAtEnd(*aarFunc->GetDummyBB()); + } else { + /* Java requires insertion at begining as it has fast unwind and other features */ + aarFunc->GetFirstBB()->InsertAtBeginning(*aarFunc->GetDummyBB()); + } } } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_call_conv.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_call_conv.cpp index 61e9efa59a1a370694fc836c630015a1cafa9bd0..36f1cd8875e36be6b92e7d416442536b56b42382 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_call_conv.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_call_conv.cpp @@ -20,246 +20,217 @@ namespace maplebe { using namespace maple; -namespace { -constexpr int kMaxRegCount = 4; - -/* - * Refer to ARM IHI 0055C_beta: Procedure Call Standard for - * ARM 64-bit Architecture. Table 1. - */ -enum AArch64ArgumentClass : uint8 { kAArch64NoClass, kAArch64IntegerClass, kAArch64FloatClass, kAArch64MemoryClass }; - -int32 ProcessNonStructAndNonArrayWhenClassifyAggregate(const MIRType &mirType, - AArch64ArgumentClass classes[kMaxRegCount], size_t classesLength) +/* external interface to look for pure float struct */ +uint32 AArch64CallConvImpl::FloatParamRegRequired(const MIRStructType &structType, uint32 &fpSize) { - CHECK_FATAL(classesLength > 0, "classLength must > 0"); - /* scalar type */ - switch (mirType.GetPrimType()) { - case PTY_u1: - case PTY_u8: - case PTY_i8: - case PTY_u16: - case PTY_i16: - case PTY_a32: - case PTY_u32: - case PTY_i32: - case PTY_a64: - case PTY_ptr: - case PTY_ref: - case PTY_u64: - case PTY_i64: - classes[0] = kAArch64IntegerClass; - return 1; - case PTY_f32: - case PTY_f64: - case PTY_c64: - case PTY_c128: - classes[0] = kAArch64FloatClass; - return 1; - default: - CHECK_FATAL(false, "NYI"); + PrimType baseType = PTY_begin; + size_t elemNum = 0; + if (!IsHomogeneousAggregates(structType, baseType, elemNum)) { + return 0; } - - /* should not reach to this point */ - return 0; + fpSize = GetPrimTypeSize(baseType); + return static_cast(elemNum); } -PrimType TraverseStructFieldsForFp(MIRType *ty, uint32 &numRegs) +static void AllocateHomogeneousAggregatesRegister(CCLocInfo &pLoc, std::vector ®List, uint32 maxRegNum, + PrimType baseType, uint32 allocNum, [[maybe_unused]] uint32 begin = 0) { - if (ty->GetKind() == kTypeArray) { - MIRArrayType *arrtype = static_cast(ty); - MIRType *pty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(arrtype->GetElemTyIdx()); - if (pty->GetKind() == kTypeArray || pty->GetKind() == kTypeStruct) { - return TraverseStructFieldsForFp(pty, numRegs); - } - for (uint32 i = 0; i < arrtype->GetDim(); ++i) { - numRegs += arrtype->GetSizeArrayItem(i); - } - return pty->GetPrimType(); - } else if (ty->GetKind() == kTypeStruct) { - MIRStructType *sttype = static_cast(ty); - FieldVector fields = sttype->GetFields(); - PrimType oldtype = PTY_void; - for (uint32 fcnt = 0; fcnt < fields.size(); ++fcnt) { - TyIdx fieldtyidx = fields[fcnt].second.first; - MIRType *fieldty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldtyidx); - PrimType ptype = TraverseStructFieldsForFp(fieldty, numRegs); - if (oldtype != PTY_void && oldtype != ptype) { - return PTY_void; - } else { - oldtype = ptype; - } - } - return oldtype; - } else { - numRegs++; - return ty->GetPrimType(); + CHECK_FATAL(allocNum + begin - 1 < maxRegNum, "NIY, out of range."); + if (allocNum >= kOneRegister) { + pLoc.reg0 = regList[begin++]; + pLoc.primTypeOfReg0 = baseType; } -} - -int32 ClassifyAggregate(const BECommon &be, MIRType &mirType, AArch64ArgumentClass classes[kMaxRegCount], - size_t classesLength, uint32 &fpSize); - -uint32 ProcessStructWhenClassifyAggregate(const BECommon &be, MIRStructType &structType, - AArch64ArgumentClass classes[kMaxRegCount], size_t classesLength, - uint32 &fpSize) -{ - CHECK_FATAL(classesLength > 0, "classLength must > 0"); - uint32 sizeOfTyInDwords = - static_cast(RoundUp(be.GetTypeSize(structType.GetTypeIndex()), k8ByteSize) >> k8BitShift); - bool isF32 = false; - bool isF64 = false; - uint32 numRegs = 0; - for (uint32 f = 0; f < structType.GetFieldsSize(); ++f) { - TyIdx fieldTyIdx = structType.GetFieldsElemt(f).second.first; - MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); - PrimType pType = TraverseStructFieldsForFp(fieldType, numRegs); - if (pType == PTY_f32) { - if (isF64) { - isF64 = false; - break; - } - isF32 = true; - } else if (pType == PTY_f64) { - if (isF32) { - isF32 = false; - break; - } - isF64 = true; - } else if (IsPrimitiveVector(pType)) { - isF64 = true; - break; - } else { - isF32 = isF64 = false; - break; - } + if (allocNum >= kTwoRegister) { + pLoc.reg1 = regList[begin++]; + pLoc.primTypeOfReg1 = baseType; } - if (isF32 || isF64) { - CHECK_FATAL(numRegs <= classesLength, "ClassifyAggregate: num regs exceed limit"); - for (uint32 i = 0; i < numRegs; ++i) { - classes[i] = kAArch64FloatClass; - } - fpSize = isF32 ? k4ByteSize : k8ByteSize; - return numRegs; + if (allocNum >= kThreeRegister) { + pLoc.reg2 = regList[begin++]; + pLoc.primTypeOfReg2 = baseType; } - - classes[0] = kAArch64IntegerClass; - if (sizeOfTyInDwords == kDwordSizeTwo) { - classes[1] = kAArch64IntegerClass; + if (allocNum >= kFourRegister) { + pLoc.reg3 = regList[begin]; + pLoc.primTypeOfReg3 = baseType; } - DEBUG_ASSERT(sizeOfTyInDwords <= classesLength, "sizeOfTyInDwords exceed limit"); - return sizeOfTyInDwords; + pLoc.regCount = static_cast(allocNum); } -/* - * Analyze the given aggregate using the rules given by the ARM 64-bit ABI and - * return the number of doublewords to be passed in registers; the classes of - * the doublewords are returned in parameter "classes"; if 0 is returned, it - * means the whole aggregate is passed in memory. - */ -int32 ClassifyAggregate(const BECommon &be, MIRType &mirType, AArch64ArgumentClass classes[kMaxRegCount], - size_t classesLength, uint32 &fpSize) +// instantiated with the type of the function return value, it describes how +// the return value is to be passed back to the caller +// Refer to Procedure Call Standard for the Arm 64-bit +// Architecture (AArch64) 2022Q3. $6.9 +// "If the type, T, of the result of a function is such that +// void func(T arg) +// would require that arg be passed as a value in a register (or set of registers) +// according to the rules in Parameter passing, then the result is returned in the +// same registers as would be used for such an argument." +void AArch64CallConvImpl::LocateRetVal(const MIRType &retType, CCLocInfo &pLoc) { - CHECK_FATAL(classesLength > 0, "invalid index"); - uint64 sizeOfTy = be.GetTypeSize(mirType.GetTypeIndex()); - /* Rule B.3. - * If the argument type is a Composite Type that is larger than 16 bytes - * then the argument is copied to memory allocated by the caller and - * the argument is replaced by a pointer to the copy. - */ - if ((sizeOfTy > k16ByteSize) || (sizeOfTy == 0)) { - return 0; + InitCCLocInfo(pLoc); + size_t retSize = retType.GetSize(); + if (retSize == 0) { + return; // size 0 ret val + } + + PrimType primType = retType.GetPrimType(); + if (IsPrimitiveFloat(primType) || IsPrimitiveVector(primType)) { + // float or vector, return in v0 + pLoc.reg0 = AArch64Abi::floatReturnRegs[0]; + pLoc.primTypeOfReg0 = primType; + pLoc.regCount = 1; + return; + } + if (IsPrimitiveInteger(primType) && GetPrimTypeBitSize(primType) <= k64BitSize) { + // interger and size <= 64-bit, return in x0 + pLoc.reg0 = AArch64Abi::intReturnRegs[0]; + pLoc.primTypeOfReg0 = primType; + pLoc.regCount = 1; + return; + } + PrimType baseType = PTY_begin; + size_t elemNum = 0; + if (IsHomogeneousAggregates(retType, baseType, elemNum)) { + // homogeneous aggregates, return in v0-v3 + AllocateHomogeneousAggregatesRegister(pLoc, AArch64Abi::floatReturnRegs, AArch64Abi::kNumFloatParmRegs, + baseType, static_cast(elemNum)); + return; } - - /* - * An argument of any Integer class takes up an integer register - * which is a single double-word. - * Rule B.4. The size of an argument of composite type is rounded up to the nearest - * multiple of 8 bytes. - */ - int64 sizeOfTyInDwords = static_cast(RoundUp(sizeOfTy, k8ByteSize) >> k8BitShift); - DEBUG_ASSERT(sizeOfTyInDwords > 0, "sizeOfTyInDwords should be sizeOfTyInDwords > 0"); - DEBUG_ASSERT(sizeOfTyInDwords <= kTwoRegister, "sizeOfTyInDwords should be <= 2"); - int64 i; - for (i = 0; i < sizeOfTyInDwords; ++i) { - classes[i] = kAArch64NoClass; - } - if ((mirType.GetKind() != kTypeStruct) && (mirType.GetKind() != kTypeArray) && (mirType.GetKind() != kTypeUnion)) { - return ProcessNonStructAndNonArrayWhenClassifyAggregate(mirType, classes, classesLength); - } - if (mirType.GetKind() == kTypeStruct) { - MIRStructType &structType = static_cast(mirType); - return static_cast(ProcessStructWhenClassifyAggregate(be, structType, classes, classesLength, fpSize)); - } - /* post merger clean-up */ - for (i = 0; i < sizeOfTyInDwords; ++i) { - if (classes[i] == kAArch64MemoryClass) { - return 0; + if (retSize <= k16ByteSize) { + // agg size <= 16-byte or int128, return in x0-x1 + pLoc.reg0 = AArch64Abi::intReturnRegs[0]; + pLoc.primTypeOfReg0 = (retSize <= k4ByteSize && !CGOptions::IsBigEndian()) ? PTY_u32 : PTY_u64; + if (retSize > k8ByteSize) { + pLoc.reg1 = AArch64Abi::intReturnRegs[1]; + pLoc.primTypeOfReg1 = (retSize <= k12ByteSize && !CGOptions::IsBigEndian()) ? PTY_u32 : PTY_u64; } + pLoc.regCount = retSize <= k8ByteSize ? kOneRegister : kTwoRegister; + return; } - return static_cast(sizeOfTyInDwords); } -} // namespace -/* external interface to look for pure float struct */ -uint32 AArch64CallConvImpl::FloatParamRegRequired(MIRStructType &structType, uint32 &fpSize) +uint64 AArch64CallConvImpl::AllocateRegisterForAgg(const MIRType &mirType, CCLocInfo &pLoc, uint64 size, uint64 &align) { - if (structType.GetSize() > k32ByteSize) { - return 0; - } - AArch64ArgumentClass classes[kMaxRegCount]; - uint32 numRegs = ProcessStructWhenClassifyAggregate(beCommon, structType, classes, kMaxRegCount, fpSize); - if (numRegs == 0) { - return 0; + uint64 aggCopySize = 0; + PrimType baseType = PTY_begin; + size_t elemNum = 0; + if (IsHomogeneousAggregates(mirType, baseType, elemNum)) { + align = GetPrimTypeSize(baseType); + if ((nextFloatRegNO + elemNum - 1) < AArch64Abi::kNumFloatParmRegs) { + // C.2 If the argument is an HFA or an HVA and there are sufficient unallocated SIMD and + // Floating-point registers (NSRN + number of members <= 8), then the argument is + // allocated to SIMD and Floating-point registers (with one register per member of + // the HFA or HVA). The NSRN is incremented by the number of registers used. + // The argument has now been allocated + AllocateHomogeneousAggregatesRegister(pLoc, AArch64Abi::floatReturnRegs, AArch64Abi::kNumFloatParmRegs, + baseType, static_cast(elemNum), nextFloatRegNO); + nextFloatRegNO = static_cast(nextFloatRegNO + elemNum); + } else { + // C.3 If the argument is an HFA or an HVA then the NSRN is set to 8 and the size of the + // argument is rounded up to the nearest multiple of 8 bytes. + nextFloatRegNO = AArch64Abi::kNumFloatParmRegs; + pLoc.reg0 = kRinvalid; + } + } else if (size <= k16ByteSize) { + // small struct, passed by general purpose register + // B.6 If the argument is an alignment adjusted type its value is passed as a copy of the actual + // value. The copy will have an alignment defined as follows: + // (1) For a Fundamental Data Type, the alignment is the natural alignment of that type, + // after any promotions. + // (2) For a Composite Type, the alignment of the copy will have 8-byte alignment if its + // natural alignment is <= 8 and 16-byte alignment if its natural alignment is >= 16. + // The alignment of the copy is used for applying marshaling rules. + if (mirType.GetUnadjustedAlign() <= k8ByteSize) { + align = k8ByteSize; + } else { + align = k16ByteSize; + } + AllocateGPRegister(mirType, pLoc, size, align); + } else { + // large struct, a pointer to the copy is used + pLoc.reg0 = AllocateGPRegister(); + pLoc.primTypeOfReg0 = PTY_a64; + pLoc.memSize = k8ByteSizeInt; + aggCopySize = RoundUp(size, k8ByteSize); } + return aggCopySize; +} - bool isPure = true; - for (uint32 i = 0; i < numRegs; ++i) { - DEBUG_ASSERT(i < kMaxRegCount, "i should be lower than kMaxRegCount"); - if (classes[i] != kAArch64FloatClass) { - isPure = false; - break; +// allocate general purpose register +void AArch64CallConvImpl::AllocateGPRegister(const MIRType &mirType, CCLocInfo &pLoc, uint64 size, uint64 align) +{ + if (IsPrimitiveInteger(mirType.GetPrimType()) && size <= k8ByteSize) { + // C.9 If the argument is an Integral or Pointer Type, the size of the argument is less + // than or equal to 8 bytes and the NGRN is less than 8, the argument is copied to + // the least significant bits in x[NGRN]. The NGRN is incremented by one. + // The argument has now been allocated. + pLoc.reg0 = AllocateGPRegister(); + pLoc.primTypeOfReg0 = mirType.GetPrimType(); + return; + } + if (align == k16ByteSize) { + // C.10 If the argument has an alignment of 16 then the NGRN is rounded up to the next + // even number. + nextGeneralRegNO = (nextGeneralRegNO + 1U) & ~1U; + } + if (mirType.GetPrimType() == PTY_i128 || mirType.GetPrimType() == PTY_u128) { + // C.11 If the argument is an Integral Type, the size of the argument is equal to 16 + // and the NGRN is less than 7, the argument is copied to x[NGRN] and x[NGRN+1]. + // x[NGRN] shall contain the lower addressed double-word of the memory + // representation of the argument. The NGRN is incremented by two. + // The argument has now been allocated. + if (nextGeneralRegNO < AArch64Abi::kNumIntParmRegs - 1) { + DEBUG_ASSERT(size == k16ByteSize, "NIY, size must be 16-byte."); + pLoc.reg0 = AllocateGPRegister(); + pLoc.primTypeOfReg0 = PTY_u64; + pLoc.reg1 = AllocateGPRegister(); + pLoc.primTypeOfReg1 = PTY_u64; + return; + } + } else if (size <= k16ByteSize) { + // C.12 If the argument is a Composite Type and the size in double-words of the argument + // is not more than 8 minus NGRN, then the argument is copied into consecutive + // general-purpose registers, starting at x[NGRN]. The argument is passed as though + // it had been loaded into the registers from a double-word-aligned address with + // an appropriate sequence of LDR instructions loading consecutive registers from + // memory (the contents of any unused parts of the registers are unspecified by this + // standard). The NGRN is incremented by the number of registers used. + // The argument has now been allocated. + DEBUG_ASSERT(mirType.GetPrimType() == PTY_agg, "NIY, primType must be PTY_agg."); + auto regNum = (size <= k8ByteSize) ? kOneRegister : kTwoRegister; + if (nextGeneralRegNO + regNum - 1 < AArch64Abi::kNumIntParmRegs) { + pLoc.reg0 = AllocateGPRegister(); + pLoc.primTypeOfReg0 = (size <= k4ByteSize && !CGOptions::IsBigEndian()) ? PTY_u32 : PTY_u64; + if (regNum == kTwoRegister) { + pLoc.reg1 = AllocateGPRegister(); + pLoc.primTypeOfReg1 = (size <= k12ByteSize && !CGOptions::IsBigEndian()) ? PTY_u32 : PTY_u64; + } + return; } } - if (isPure) { - return numRegs; - } - return 0; + + // C.13 The NGRN is set to 8. + pLoc.reg0 = kRinvalid; + nextGeneralRegNO = AArch64Abi::kNumIntParmRegs; } -int32 AArch64CallConvImpl::LocateRetVal(MIRType &retType, CCLocInfo &pLoc) +static void SetupCCLocInfoRegCount(CCLocInfo &pLoc) { - InitCCLocInfo(pLoc); - uint32 retSize = beCommon.GetTypeSize(retType.GetTypeIndex().GetIdx()); - if (retSize == 0) { - return 0; /* size 0 ret val */ + if (pLoc.reg0 == kRinvalid) { + return; } - if (retSize <= k16ByteSize) { - /* For return struct size less or equal to 16 bytes, the values */ - /* are returned in register pairs. */ - AArch64ArgumentClass classes[kMaxRegCount] = {kAArch64NoClass}; /* Max of four floats. */ - uint32 fpSize; - uint32 numRegs = static_cast(ClassifyAggregate(beCommon, retType, classes, sizeof(classes), fpSize)); - if (classes[0] == kAArch64FloatClass) { - CHECK_FATAL(numRegs <= kMaxRegCount, "LocateNextParm: illegal number of regs"); - AllocateNSIMDFPRegisters(pLoc, numRegs); - pLoc.numFpPureRegs = numRegs; - pLoc.fpSize = fpSize; - return 0; - } else { - CHECK_FATAL(numRegs <= kTwoRegister, "LocateNextParm: illegal number of regs"); - if (numRegs == kOneRegister) { - pLoc.reg0 = AllocateGPRegister(); - } else { - AllocateTwoGPRegisters(pLoc); - } - return 0; - } - } else { - /* For return struct size > 16 bytes the pointer returns in x8. */ - pLoc.reg0 = R8; - return GetPointerSize(); + pLoc.regCount = kOneRegister; + if (pLoc.reg1 == kRinvalid) { + return; } + pLoc.regCount++; + if (pLoc.reg2 == kRinvalid) { + return; + } + pLoc.regCount++; + if (pLoc.reg3 == kRinvalid) { + return; + } + pLoc.regCount++; } /* @@ -283,373 +254,50 @@ int32 AArch64CallConvImpl::LocateRetVal(MIRType &retType, CCLocInfo &pLoc) * or it will be checking the caller's enclosing function. */ -int32 AArch64CallConvImpl::LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFunction *tFunc) +uint64 AArch64CallConvImpl::LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFuncType *tFunc) { InitCCLocInfo(pLoc); - // C calling convention. - bool is64x1vec = false; - - if (isFirst) { - MIRFunction *func = tFunc != nullptr ? tFunc : const_cast(beCommon.GetMIRModule().CurFunction()); - if (func->IsFirstArgReturn()) { - TyIdx tyIdx = func->GetFuncRetStructTyIdx(); - size_t size = beCommon.GetTypeSize(tyIdx); - if (size == 0) { - /* For return struct size 0 there is no return value. */ - return 0; - } - /* For return struct size > 16 bytes the pointer returns in x8. */ - pLoc.reg0 = R8; - return GetPointerSize(); - } - } - uint64 typeSize = beCommon.GetTypeSize(mirType.GetTypeIndex()); + uint64 typeSize = mirType.GetSize(); if (typeSize == 0) { return 0; } - int32 typeAlign = beCommon.GetTypeAlign(mirType.GetTypeIndex()); - /* - * Rule C.12 states that we do round nextStackArgAdress up before we use its value - * according to the alignment requirement of the argument being processed. - * We do the rounding up at the end of LocateNextParm(), - * so we want to make sure our rounding up is correct. - */ - DEBUG_ASSERT((nextStackArgAdress & (std::max(typeAlign, static_cast(k8ByteSize)) - 1)) == 0, - "C.12 alignment requirement is violated"); - pLoc.memSize = static_cast(typeSize); - ++paramNum; - int32 aggCopySize = 0; - switch (mirType.GetPrimType()) { - case PTY_u1: - case PTY_u8: - case PTY_i8: - case PTY_u16: - case PTY_i16: - case PTY_a32: - case PTY_u32: - case PTY_i32: - case PTY_ptr: - case PTY_ref: - case PTY_a64: - case PTY_u64: - case PTY_i64: - case PTY_i128: - case PTY_u128: - /* Rule C.7 */ - typeSize = k8ByteSize; - pLoc.reg0 = is64x1vec ? AllocateSIMDFPRegister() : AllocateGPRegister(); - DEBUG_ASSERT(nextGeneralRegNO <= AArch64Abi::kNumIntParmRegs, "RegNo should be pramRegNO"); - break; - /* - * for c64 complex numbers, we assume - * - callers marshall the two f32 numbers into one f64 register - * - callees de-marshall one f64 value into the real and the imaginery part - */ - case PTY_f32: - case PTY_f64: - case PTY_c64: - case PTY_v2i32: - case PTY_v4i16: - case PTY_v8i8: - case PTY_v2u32: - case PTY_v4u16: - case PTY_v8u8: - case PTY_v2f32: - /* Rule C.1 */ - DEBUG_ASSERT(GetPrimTypeSize(PTY_f64) == k8ByteSize, "unexpected type size"); - typeSize = k8ByteSize; - pLoc.reg0 = AllocateSIMDFPRegister(); - break; - /* - * for c128 complex numbers, we assume - * - callers marshall the two f64 numbers into one f128 register - * - callees de-marshall one f128 value into the real and the imaginery part - */ - case PTY_c128: - case PTY_v2i64: - case PTY_v4i32: - case PTY_v8i16: - case PTY_v16i8: - case PTY_v2u64: - case PTY_v4u32: - case PTY_v8u16: - case PTY_v16u8: - case PTY_v2f64: - case PTY_v4f32: - /* SIMD-FP registers have 128-bits. */ - pLoc.reg0 = AllocateSIMDFPRegister(); - DEBUG_ASSERT(nextFloatRegNO <= AArch64Abi::kNumFloatParmRegs, - "regNO should not be greater than kNumFloatParmRegs"); - DEBUG_ASSERT(typeSize == k16ByteSize, "unexpected type size"); - break; - /* - * case of quad-word integer: - * we don't support java yet. - * if (has-16-byte-alignment-requirement) - * nextGeneralRegNO = (nextGeneralRegNO+1) & ~1; // C.8 round it up to the next even number - * try allocate two consecutive registers at once. - */ - /* case PTY_agg */ - case PTY_agg: { - aggCopySize = ProcessPtyAggWhenLocateNextParm(mirType, pLoc, typeSize, typeAlign); - break; + if (isFirst) { + auto *func = (tFunc != nullptr) ? tFunc : beCommon.GetMIRModule().CurFunction()->GetMIRFuncType(); + if (func->FirstArgReturn()) { + // For return struct in memory, the pointer returns in x8. + SetupToReturnThroughMemory(pLoc); + return GetPointerSize(); } - default: - CHECK_FATAL(false, "NYI"); } - /* Rule C.12 */ - if (pLoc.reg0 == kRinvalid) { - /* being passed in memory */ - nextStackArgAdress = pLoc.memOffset + static_cast(static_cast(typeSize)); - } - return aggCopySize; -} + uint64 typeAlign = mirType.GetAlign(); -int32 AArch64CallConvImpl::ProcessPtyAggWhenLocateNextParm(MIRType &mirType, CCLocInfo &pLoc, uint64 &typeSize, - int32 typeAlign) -{ - /* - * In AArch64, integer-float or float-integer - * argument passing is not allowed. All should go through - * integer-integer. - * In the case where a struct is homogeneous composed of one of the fp types, - * either all single fp or all double fp, then it can be passed by float-float. - */ - AArch64ArgumentClass classes[kMaxRegCount] = {kAArch64NoClass}; - typeSize = beCommon.GetTypeSize(mirType.GetTypeIndex().GetIdx()); - int32 aggCopySize = 0; - if (typeSize > k16ByteSize) { - aggCopySize = static_cast(RoundUp(typeSize, GetPointerSize())); - } - /* - * alignment requirement - * Note. This is one of a few things iOS diverges from - * the ARM 64-bit standard. They don't observe the round-up requirement. - */ - if (typeAlign == k16ByteSize) { - RoundNGRNUpToNextEven(); - } + pLoc.memSize = static_cast(typeSize); - uint32 fpSize; - uint32 numRegs = static_cast( - ClassifyAggregate(beCommon, mirType, classes, sizeof(classes) / sizeof(AArch64ArgumentClass), fpSize)); - if (classes[0] == kAArch64FloatClass) { - CHECK_FATAL(numRegs <= kMaxRegCount, "LocateNextParm: illegal number of regs"); - typeSize = k8ByteSize; - AllocateNSIMDFPRegisters(pLoc, numRegs); - pLoc.numFpPureRegs = numRegs; - pLoc.fpSize = fpSize; - } else if (numRegs == 1) { - /* passing in registers */ - typeSize = k8ByteSize; - if (classes[0] == kAArch64FloatClass) { - CHECK_FATAL(false, "param passing in FP reg not allowed here"); - } else { - pLoc.reg0 = AllocateGPRegister(); - /* Rule C.11 */ - DEBUG_ASSERT((pLoc.reg0 != kRinvalid) || (nextGeneralRegNO == AArch64Abi::kNumIntParmRegs), - "reg0 should not be kRinvalid or nextGeneralRegNO should equal kNumIntParmRegs"); - } - } else if (numRegs == kTwoRegister) { - /* Other aggregates with 8 < size <= 16 bytes can be allocated in reg pair */ - DEBUG_ASSERT(classes[0] == kAArch64IntegerClass || classes[0] == kAArch64NoClass, - "classes[0] must be either integer class or no class"); - DEBUG_ASSERT(classes[1] == kAArch64IntegerClass || classes[1] == kAArch64NoClass, - "classes[1] must be either integer class or no class"); - AllocateTwoGPRegisters(pLoc); - /* Rule C.11 */ - if (pLoc.reg0 == kRinvalid) { - nextGeneralRegNO = AArch64Abi::kNumIntParmRegs; - } + uint64 aggCopySize = 0; + if (IsPrimitiveFloat(mirType.GetPrimType()) || IsPrimitiveVector(mirType.GetPrimType())) { + // float or vector, passed by float or SIMD register + pLoc.reg0 = AllocateSIMDFPRegister(); + pLoc.primTypeOfReg0 = mirType.GetPrimType(); + } else if (IsPrimitiveInteger(mirType.GetPrimType())) { + // integer, passed by general purpose register + AllocateGPRegister(mirType, pLoc, typeSize, typeAlign); } else { - /* - * 0 returned from ClassifyAggregate(). This means the whole data - * is passed thru memory. - * Rule B.3. - * If the argument type is a Composite Type that is larger than 16 - * bytes then the argument is copied to memory allocated by the - * caller and the argument is replaced by a pointer to the copy. - * - * Try to allocate an integer register - */ - typeSize = k8ByteSize; - pLoc.reg0 = AllocateGPRegister(); - pLoc.memSize = k8ByteSizeInt; /* byte size of a pointer in AArch64 */ - if (pLoc.reg0 != kRinvalid) { - numRegs = 1; - } + CHECK_FATAL(mirType.GetPrimType() == PTY_agg, "NIY"); + aggCopySize = AllocateRegisterForAgg(mirType, pLoc, typeSize, typeAlign); } - /* compute rightpad */ - if ((numRegs == 0) || (pLoc.reg0 == kRinvalid)) { - /* passed in memory */ - typeSize = RoundUp(static_cast(static_cast(pLoc.memSize)), k8ByteSize); - } - return aggCopySize; -} -/* - * instantiated with the type of the function return value, it describes how - * the return value is to be passed back to the caller - * - * Refer to ARM IHI 0055C_beta: Procedure Call Standard for - * the ARM 64-bit Architecture. $5.5 - * "If the type, T, of the result of a function is such that - * void func(T arg) - * would require that 'arg' be passed as a value in a register - * (or set of registers) according to the rules in $5.4 Parameter - * Passing, then the result is returned in the same registers - * as would be used for such an argument. - */ -void AArch64CallConvImpl::InitReturnInfo(MIRType &retTy, CCLocInfo &ccLocInfo) -{ - PrimType pType = retTy.GetPrimType(); - switch (pType) { - case PTY_void: - break; - case PTY_u1: - case PTY_u8: - case PTY_i8: - case PTY_u16: - case PTY_i16: - case PTY_a32: - case PTY_u32: - case PTY_i32: - ccLocInfo.regCount = 1; - ccLocInfo.reg0 = AArch64Abi::intReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = IsSignedInteger(pType) ? PTY_i32 : PTY_u32; /* promote the type */ - return; - - case PTY_ptr: - case PTY_ref: - CHECK_FATAL(false, "PTY_ptr should have been lowered"); - return; - - case PTY_a64: - case PTY_u64: - case PTY_i64: - case PTY_i128: - case PTY_u128: - ccLocInfo.regCount = 1; - ccLocInfo.reg0 = AArch64Abi::intReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = IsSignedInteger(pType) ? PTY_i64 : PTY_u64; /* promote the type */ - return; - - /* - * for c64 complex numbers, we assume - * - callers marshall the two f32 numbers into one f64 register - * - callees de-marshall one f64 value into the real and the imaginery part - */ - case PTY_f32: - case PTY_f64: - case PTY_c64: - case PTY_v2i32: - case PTY_v4i16: - case PTY_v8i8: - case PTY_v2u32: - case PTY_v4u16: - case PTY_v8u8: - case PTY_v2f32: - - /* - * for c128 complex numbers, we assume - * - callers marshall the two f64 numbers into one f128 register - * - callees de-marshall one f128 value into the real and the imaginery part - */ - case PTY_c128: - case PTY_v2i64: - case PTY_v4i32: - case PTY_v8i16: - case PTY_v16i8: - case PTY_v2u64: - case PTY_v4u32: - case PTY_v8u16: - case PTY_v16u8: - case PTY_v2f64: - case PTY_v4f32: - ccLocInfo.regCount = 1; - ccLocInfo.reg0 = AArch64Abi::floatReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = pType; - return; - - /* - * Refer to ARM IHI 0055C_beta: Procedure Call Standard for - * the ARM 64-bit Architecture. $5.5 - * "Otherwise, the caller shall reserve a block of memory of - * sufficient size and alignment to hold the result. The - * address of the memory block shall be passed as an additional - * argument to the function in x8. The callee may modify the - * result memory block at any point during the execution of the - * subroutine (there is no requirement for the callee to preserve - * the value stored in x8)." - */ - case PTY_agg: { - uint64 size = beCommon.GetTypeSize(retTy.GetTypeIndex()); - if ((size > k16ByteSize) || (size == 0)) { - /* - * The return value is returned via memory. - * The address is in X8 and passed by the caller. - */ - SetupToReturnThroughMemory(ccLocInfo); - return; - } - uint32 fpSize; - AArch64ArgumentClass classes[kMaxRegCount] = {kAArch64NoClass}; - ccLocInfo.regCount = static_cast( - ClassifyAggregate(beCommon, retTy, classes, sizeof(classes) / sizeof(AArch64ArgumentClass), fpSize)); - if (classes[0] == kAArch64FloatClass) { - switch (ccLocInfo.regCount) { - case kFourRegister: - ccLocInfo.reg3 = AArch64Abi::floatReturnRegs[kFourthReg]; - break; - case kThreeRegister: - ccLocInfo.reg2 = AArch64Abi::floatReturnRegs[kThirdReg]; - break; - case kTwoRegister: - ccLocInfo.reg1 = AArch64Abi::floatReturnRegs[kSecondReg]; - break; - case kOneRegister: - ccLocInfo.reg0 = AArch64Abi::floatReturnRegs[kFirstReg]; - break; - default: - CHECK_FATAL(0, "AArch64CallConvImpl: unsupported"); - } - if (fpSize == k4ByteSize) { - ccLocInfo.primTypeOfReg0 = ccLocInfo.primTypeOfReg1 = PTY_f32; - } else { - ccLocInfo.primTypeOfReg0 = ccLocInfo.primTypeOfReg1 = PTY_f64; - } - return; - } else if (ccLocInfo.regCount == 0) { - SetupToReturnThroughMemory(ccLocInfo); - return; - } else { - if (ccLocInfo.regCount == 1) { - /* passing in registers */ - if (classes[0] == kAArch64FloatClass) { - ccLocInfo.reg0 = AArch64Abi::floatReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = PTY_f64; - } else { - ccLocInfo.reg0 = AArch64Abi::intReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = PTY_i64; - } - } else { - DEBUG_ASSERT(ccLocInfo.regCount <= k2ByteSize, - "reg count from ClassifyAggregate() should be 0, 1, or 2"); - DEBUG_ASSERT(classes[0] == kAArch64IntegerClass, "error val :classes[0]"); - DEBUG_ASSERT(classes[1] == kAArch64IntegerClass, "error val :classes[1]"); - ccLocInfo.reg0 = AArch64Abi::intReturnRegs[0]; - ccLocInfo.primTypeOfReg0 = PTY_i64; - ccLocInfo.reg1 = AArch64Abi::intReturnRegs[1]; - ccLocInfo.primTypeOfReg1 = PTY_i64; - } - return; - } - } - default: - CHECK_FATAL(false, "NYI"); + SetupCCLocInfoRegCount(pLoc); + if (pLoc.reg0 == kRinvalid) { + // being passed in memory + typeAlign = (typeAlign <= k8ByteSize) ? k8ByteSize : typeAlign; + nextStackArgAdress = RoundUp(nextStackArgAdress, typeAlign); + pLoc.memOffset = static_cast(nextStackArgAdress); + // large struct, passed with pointer + nextStackArgAdress += (aggCopySize != 0 ? k8ByteSize : typeSize); } + return aggCopySize; } void AArch64CallConvImpl::SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc) const @@ -680,7 +328,7 @@ void AArch64CallConvImpl::SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pL } } -int32 AArch64WebKitJSCC::LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFunction *tFunc) +uint64 AArch64WebKitJSCC::LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFuncType *tFunc) { std::vector classes {}; int32 alignedTySize = ClassificationArg(beCommon, mirType, classes); @@ -702,20 +350,20 @@ int32 AArch64WebKitJSCC::LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool return 0; } -int32 AArch64WebKitJSCC::LocateRetVal(MIRType &retType, CCLocInfo &pLoc) +void AArch64WebKitJSCC::LocateRetVal(const MIRType &retType, CCLocInfo &pLoc) { InitCCLocInfo(pLoc); std::vector classes {}; /* Max of four Regs. */ int32 alignedTySize = ClassificationRet(beCommon, retType, classes); if (alignedTySize == 0) { - return 0; /* size 0 ret val */ + return; /* size 0 ret val */ } if (classes[0] == kIntegerClass) { if ((alignedTySize == k4ByteSize) || (alignedTySize == k8ByteSize)) { pLoc.reg0 = AllocateGPRetRegister(); pLoc.regCount += 1; pLoc.primTypeOfReg0 = alignedTySize == k4ByteSize ? PTY_i32 : PTY_i64; - } else { + } else { CHECK_FATAL(false, "should not go here"); } } else if (classes[0] == kFloatClass) { @@ -723,17 +371,17 @@ int32 AArch64WebKitJSCC::LocateRetVal(MIRType &retType, CCLocInfo &pLoc) pLoc.reg0 = AllocateSIMDFPRetRegister(); pLoc.regCount += 1; pLoc.primTypeOfReg0 = alignedTySize == k4ByteSize ? PTY_f32 : PTY_f64; - } else { + } else { CHECK_FATAL(false, "should not go here"); } } if (pLoc.reg0 == kRinvalid || classes[0] == kMemoryClass) { CHECK_FATAL(false, "should not happen"); } - return 0; + return; } -int32 AArch64WebKitJSCC::ClassificationRet(const BECommon &be, MIRType &mirType, +int32 AArch64WebKitJSCC::ClassificationRet(const BECommon &be, const MIRType &mirType, std::vector &classes) const { switch (mirType.GetPrimType()) { @@ -763,7 +411,7 @@ int32 AArch64WebKitJSCC::ClassificationRet(const BECommon &be, MIRType &mirType, } } -int32 AArch64WebKitJSCC::ClassificationArg(const BECommon &be, MIRType &mirType, +int32 AArch64WebKitJSCC::ClassificationArg(const BECommon &be, const MIRType &mirType, std::vector &classes) const { switch (mirType.GetPrimType()) { @@ -813,7 +461,7 @@ void AArch64WebKitJSCC::SetupSecondRetReg(const MIRType &retTy2, CCLocInfo &pLoc return; } -int32 GHCCC::LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFunction *tFunc) +uint64 GHCCC::LocateNextParm(const MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIRFuncType *tFunc) { std::vector classes {}; int32 alignedTySize = ClassificationArg(beCommon, mirType, classes); @@ -842,13 +490,12 @@ int32 GHCCC::LocateNextParm(MIRType &mirType, CCLocInfo &pLoc, bool isFirst, MIR return 0; } -int32 GHCCC::LocateRetVal(MIRType &retType, CCLocInfo &pLoc) +void GHCCC::LocateRetVal(const MIRType &retType, CCLocInfo &pLoc) { CHECK_FATAL(false, "GHC does not return"); - return 0; } -int32 GHCCC::ClassificationArg(const BECommon &be, MIRType &mirType, std::vector &classes) const +int32 GHCCC::ClassificationArg(const BECommon &be, const MIRType &mirType, std::vector &classes) const { switch (mirType.GetPrimType()) { /* diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp index af0f28855324e73b05f61844a1b7faee05764dbb..7995dc49b2ac9fe8275a3a8234751d91218f21a0 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp @@ -161,6 +161,23 @@ bool IsBlkassignForPush(const BlkassignoffNode &bNode) return spBased; } +void AArch64CGFunc::SetMemReferenceOfInsn(Insn &insn, BaseNode *baseNode) +{ + if (baseNode == nullptr) { + return; + } + MIRFunction &mirFunction = GetFunction(); + MemReferenceTable *memRefTable = mirFunction.GetMemReferenceTable(); + // In O0 mode, we do not run the ME, and the referenceTable is nullptr + if (memRefTable == nullptr) { + return; + } + MemDefUsePart &memDefUsePart = memRefTable->GetMemDefUsePart(); + if (memDefUsePart.find(baseNode) != memDefUsePart.end()) { + insn.SetReferenceOsts(memDefUsePart.find(baseNode)->second); + } +} + MIRStructType *AArch64CGFunc::GetLmbcStructArgType(BaseNode &stmt, size_t argNo) const { MIRType *ty = nullptr; @@ -429,7 +446,7 @@ void AArch64CGFunc::SelectCopyImm(Operand &dest, ImmOperand &src, PrimType dtype return; } if (src.IsSingleInstructionMovable()) { - MOperator mOp = (dsize == k32BitSize) ? MOP_wmovri32 : MOP_xmovri64; + MOperator mOp = (dsize <= k32BitSize) ? MOP_wmovri32 : MOP_xmovri64; GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mOp, dest, src)); return; } @@ -1077,14 +1094,14 @@ void AArch64CGFunc::SelectDassign(DassignNode &stmt, Operand &opnd0) SelectDassign(stmt.GetStIdx(), stmt.GetFieldID(), stmt.GetRHS()->GetPrimType(), opnd0); } -/* - * Used for SelectDassign when do optimization for volatile store, because the stlr instruction only allow - * store to the memory addrress with the register base offset 0. - * STLR , [{,#0}], 32-bit variant (size = 10) - * STLR , [{,#0}], 64-bit variant (size = 11) - * So the function do the prehandle of the memory operand to satisify the Store-Release.. +/* Extract the address of memOpnd. + * 1. memcpy need address from memOpnd + * 2. Used for SelectDassign when do optimization for volatile store, because the stlr instruction only allow + * store to the memory addrress with the register base offset 0. + * STLR , [{,#0}], 32-bit variant (size = 10) + * STLR , [{,#0}], 64-bit variant (size = 11) */ -RegOperand *AArch64CGFunc::ExtractNewMemBase(const MemOperand &memOpnd) +RegOperand *AArch64CGFunc::ExtractMemBaseAddr(const MemOperand &memOpnd) { const MIRSymbol *sym = memOpnd.GetSymbol(); MemOperand::AArch64AddressingMode mode = memOpnd.GetAddrMode(); @@ -1179,7 +1196,7 @@ void AArch64CGFunc::SelectDassign(StIdx stIdx, FieldID fieldId, PrimType rhsPTyp AArch64isa::MemoryOrdering memOrd = AArch64isa::kMoNone; if (isVolStore) { - RegOperand *baseOpnd = ExtractNewMemBase(*memOpnd); + RegOperand *baseOpnd = ExtractMemBaseAddr(*memOpnd); if (baseOpnd != nullptr) { memOpnd = &CreateMemOpnd(*baseOpnd, 0, dataSize); memOrd = AArch64isa::kMoRelease; @@ -1672,6 +1689,19 @@ void AArch64CGFunc::SelectRegassign(RegassignNode &stmt, Operand &opnd0) } } +MemOperand *AArch64CGFunc::GenFormalMemOpndWithSymbol(const MIRSymbol &sym, int64 offset) +{ + MemOperand *memOpnd = nullptr; + if (IsParamStructCopy(sym)) { + memOpnd = &GetOrCreateMemOpnd(sym, 0, k64BitSize); + RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); + Insn &ldInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *memOpnd); + GetCurBB()->AppendInsn(ldInsn); + return CreateMemOperand(k64BitSize, *vreg, CreateImmOperand(offset, k32BitSize, false), sym.IsVolatile()); + } + return &GetOrCreateMemOpnd(sym, offset, k64BitSize); +} + MemOperand *AArch64CGFunc::FixLargeMemOpnd(MemOperand &memOpnd, uint32 align) { MemOperand *lhsMemOpnd = &memOpnd; @@ -1760,6 +1790,33 @@ Insn *AArch64CGFunc::AggtStrLdrInsert(bool bothUnion, Insn *lastStrLdr, Insn &ne return &newStrLdr; } +MemOperand *AArch64CGFunc::SelectRhsMemOpnd(BaseNode &rhsStmt, bool &isRefField) +{ + MemOperand *rhsMemOpnd = nullptr; + if (rhsStmt.GetOpCode() == OP_dread) { + MemRWNodeHelper rhsMemHelper(rhsStmt, GetFunction(), GetBecommon()); + auto *rhsSymbol = rhsMemHelper.GetSymbol(); + rhsMemOpnd = GenFormalMemOpndWithSymbol(*rhsSymbol, rhsMemHelper.GetByteOffset()); + isRefField = rhsMemHelper.IsRefField(); + } else { + DEBUG_ASSERT(rhsStmt.GetOpCode() == OP_iread, "SelectRhsMemOpnd: NYI"); + auto &rhsIread = static_cast(rhsStmt); + MemRWNodeHelper rhsMemHelper(rhsIread, GetFunction(), GetBecommon()); + auto *rhsAddrOpnd = HandleExpr(rhsIread, *rhsIread.Opnd(0)); + auto &rhsAddr = LoadIntoRegister(*rhsAddrOpnd, rhsIread.Opnd(0)->GetPrimType()); + auto &rhsOfstOpnd = CreateImmOperand(rhsMemHelper.GetByteOffset(), k32BitSize, false); + rhsMemOpnd = CreateMemOperand(k64BitSize, rhsAddr, rhsOfstOpnd, rhsIread.IsVolatile()); + isRefField = rhsMemHelper.IsRefField(); + } + return rhsMemOpnd; +} + +MemOperand *AArch64CGFunc::SelectRhsMemOpnd(BaseNode &rhsStmt) +{ + bool isRefField = false; + return SelectRhsMemOpnd(rhsStmt, isRefField); +} + CCImpl *AArch64CGFunc::GetOrCreateLocator(CallConvKind cc) { auto it = hashCCTable.find(cc); @@ -2584,7 +2641,8 @@ void AArch64CGFunc::SelectAggIassign(IassignNode &stmt, Operand &AddrOpnd) CHECK_FATAL(lhsSize <= k16ByteSize, "SelectAggIassign: illegal struct size"); AArch64CallConvImpl parmlocator(GetBecommon()); CCLocInfo pLoc; - parmlocator.LocateNextParm(*lhsType, pLoc, true, GetBecommon().GetMIRModule().CurFunction()); + parmlocator.LocateNextParm(*lhsType, pLoc, true, + GetBecommon().GetMIRModule().CurFunction()->GetMIRFuncType()); /* aggregates are 8 byte aligned. */ Operand *rhsmemopnd = nullptr; RegOperand *result[kFourRegister]; /* up to 2 int or 4 fp */ @@ -2882,160 +2940,67 @@ void AArch64CGFunc::SelectAggIassign(IassignNode &stmt, Operand &AddrOpnd) void AArch64CGFunc::SelectReturnSendOfStructInRegs(BaseNode *x) { - uint32 offset = 0; - if (x->GetOpCode() == OP_dread) { - DreadNode *dread = static_cast(x); - MIRSymbol *sym = GetFunction().GetLocalOrGlobalSymbol(dread->GetStIdx()); - MIRType *mirType = sym->GetType(); - if (dread->GetFieldID() != 0) { - MIRStructType *structType = static_cast(mirType); - mirType = structType->GetFieldType(dread->GetFieldID()); - offset = static_cast(GetBecommon().GetFieldOffset(*structType, dread->GetFieldID()).first); - } - uint32 typeSize = GetBecommon().GetTypeSize(mirType->GetTypeIndex()); - /* generate move to regs for agg return */ - AArch64CallConvImpl parmlocator(GetBecommon()); - CCLocInfo pLoc; - (void)parmlocator.LocateNextParm(*mirType, pLoc, true, GetBecommon().GetMIRModule().CurFunction()); - /* aggregates are 8 byte aligned. */ - Operand *rhsmemopnd = nullptr; - RegOperand *result[kFourRegister]; /* up to 2 int or 4 fp */ - uint32 loadSize; - uint32 numRegs; - RegType regType; - PrimType retPty; - bool fpParm = false; - if (pLoc.numFpPureRegs) { - loadSize = pLoc.fpSize; - numRegs = pLoc.numFpPureRegs; - fpParm = true; - regType = kRegTyFloat; - retPty = (pLoc.fpSize == k4ByteSize) ? PTY_f32 : PTY_f64; - } else { - if (CGOptions::IsBigEndian()) { - loadSize = k8ByteSize; - numRegs = (typeSize <= k8ByteSize) ? kOneRegister : kTwoRegister; - regType = kRegTyInt; - retPty = PTY_u64; - } else { - loadSize = (typeSize <= k4ByteSize) ? k4ByteSize : k8ByteSize; - numRegs = (typeSize <= k8ByteSize) ? kOneRegister : kTwoRegister; - regType = kRegTyInt; - retPty = PTY_u32; - } - } - bool parmCopy = IsParamStructCopy(*sym); - for (uint32 i = 0; i < numRegs; i++) { - if (parmCopy) { - rhsmemopnd = - &LoadStructCopyBase(*sym, (offset + static_cast(i * (fpParm ? loadSize : k8ByteSize))), - static_cast(loadSize * kBitsPerByte)); - } else { - rhsmemopnd = - &GetOrCreateMemOpnd(*sym, (offset + static_cast(i * (fpParm ? loadSize : k8ByteSize))), - (loadSize * kBitsPerByte)); - } - result[i] = &CreateVirtualRegisterOperand(NewVReg(regType, loadSize)); - MOperator mop1 = PickLdInsn(loadSize * kBitsPerByte, retPty); - Insn &ld = GetInsnBuilder()->BuildInsn(mop1, *(result[i]), *rhsmemopnd); - GetCurBB()->AppendInsn(ld); - } - AArch64reg regs[kFourRegister]; - regs[kFirstReg] = static_cast(pLoc.reg0); - regs[kSecondReg] = static_cast(pLoc.reg1); - regs[kThirdReg] = static_cast(pLoc.reg2); - regs[kFourthReg] = static_cast(pLoc.reg3); - RegOperand *dest; - for (uint32 i = 0; i < numRegs; i++) { - AArch64reg preg; - MOperator mop2; - if (fpParm) { - preg = regs[i]; - mop2 = (loadSize == k4ByteSize) ? MOP_xvmovs : MOP_xvmovd; - } else { - preg = (i == 0 ? R0 : R1); - mop2 = (loadSize == k4ByteSize) ? MOP_wmovrr : MOP_xmovrr; - } - dest = &GetOrCreatePhysicalRegisterOperand(preg, (loadSize * kBitsPerByte), regType); - Insn &mov = GetInsnBuilder()->BuildInsn(mop2, *dest, *(result[i])); - GetCurBB()->AppendInsn(mov); - } - /* Create artificial dependency to extend the live range */ - for (uint32 i = 0; i < numRegs; i++) { - AArch64reg preg; - MOperator mop3; - if (fpParm) { - preg = regs[i]; - mop3 = MOP_pseudo_ret_float; - } else { - preg = (i == 0 ? R0 : R1); - mop3 = MOP_pseudo_ret_int; - } - dest = &GetOrCreatePhysicalRegisterOperand(preg, loadSize * kBitsPerByte, regType); - Insn &pseudo = GetInsnBuilder()->BuildInsn(mop3, *dest); - GetCurBB()->AppendInsn(pseudo); - } - return; - } else if (x->GetOpCode() == OP_iread) { - IreadNode *iread = static_cast(x); - RegOperand *rhsAddrOpnd = static_cast(HandleExpr(*iread, *iread->Opnd(0))); - rhsAddrOpnd = &LoadIntoRegister(*rhsAddrOpnd, iread->Opnd(0)->GetPrimType()); - MIRPtrType *ptrType = - static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->GetTyIdx())); - MIRType *mirType = static_cast(ptrType->GetPointedType()); - bool isRefField = false; - if (iread->GetFieldID() != 0) { - MIRStructType *structType = static_cast(mirType); - mirType = structType->GetFieldType(iread->GetFieldID()); - offset = static_cast(GetBecommon().GetFieldOffset(*structType, iread->GetFieldID()).first); - isRefField = GetBecommon().IsRefField(*structType, iread->GetFieldID()); - } - uint32 typeSize = GetBecommon().GetTypeSize(mirType->GetTypeIndex()); - /* generate move to regs. */ - RegOperand *result[kTwoRegister]; /* maximum 16 bytes, 2 registers */ - uint32 loadSize; - if (CGOptions::IsBigEndian()) { - loadSize = k8ByteSize; - } else { - loadSize = (typeSize <= k4ByteSize) ? k4ByteSize : k8ByteSize; - } - uint32 numRegs = (typeSize <= k8ByteSize) ? kOneRegister : kTwoRegister; - for (uint32 i = 0; i < numRegs; i++) { - OfstOperand *rhsOffOpnd = &GetOrCreateOfstOpnd(offset + i * loadSize, loadSize * kBitsPerByte); - Operand &rhsmemopnd = GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, loadSize * kBitsPerByte, rhsAddrOpnd, - nullptr, rhsOffOpnd, nullptr); - result[i] = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, loadSize)); - MOperator mop1 = PickLdInsn(loadSize * kBitsPerByte, PTY_u32); - Insn &ld = GetInsnBuilder()->BuildInsn(mop1, *(result[i]), rhsmemopnd); - ld.MarkAsAccessRefField(isRefField); - GetCurBB()->AppendInsn(ld); - if (!VERIFY_INSN(&ld)) { - SPLIT_INSN(&ld, this); - } - } - RegOperand *dest; - for (uint32 i = 0; i < numRegs; i++) { - AArch64reg preg = (i == 0 ? R0 : R1); - dest = &GetOrCreatePhysicalRegisterOperand(preg, loadSize * kBitsPerByte, kRegTyInt); - Insn &mov = GetInsnBuilder()->BuildInsn(MOP_xmovrr, *dest, *(result[i])); - GetCurBB()->AppendInsn(mov); - } - /* Create artificial dependency to extend the live range */ - for (uint32 i = 0; i < numRegs; i++) { - AArch64reg preg = (i == 0 ? R0 : R1); - dest = &GetOrCreatePhysicalRegisterOperand(preg, loadSize * kBitsPerByte, kRegTyInt); - Insn &pseudo = GetInsnBuilder()->BuildInsn(MOP_pseudo_ret_int, *dest); - GetCurBB()->AppendInsn(pseudo); - } - return; - } else { // dummy return of 0 inserted by front-end at absence of return - DEBUG_ASSERT(x->GetOpCode() == OP_constval, "SelectReturnSendOfStructInRegs: unexpected return operand"); - uint32 typeSize = GetPrimTypeSize(x->GetPrimType()); - RegOperand &dest = GetOrCreatePhysicalRegisterOperand(R0, typeSize * kBitsPerByte, kRegTyInt); - ImmOperand &src = CreateImmOperand(0, k16BitSize, false); + if (x->GetOpCode() != OP_dread && x->GetOpCode() != OP_iread) { + // dummy return of 0 inserted by front-end at absence of return + DEBUG_ASSERT(x->GetOpCode() == OP_constval, "NIY: unexpected return operand"); + uint32 typeSize = GetPrimTypeBitSize(x->GetPrimType()); + RegOperand &dest = GetOrCreatePhysicalRegisterOperand(R0, typeSize, kRegTyInt); + ImmOperand &src = CreateImmOperand(0, typeSize, false); GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, dest, src)); return; } + + MemRWNodeHelper helper(*x, GetFunction(), GetBecommon()); + bool isRefField = false; + auto *addrOpnd = SelectRhsMemOpnd(*x, isRefField); + + // generate move to regs for agg return + AArch64CallConvImpl parmlocator(GetBecommon()); + CCLocInfo retMatch; + parmlocator.LocateRetVal(*helper.GetMIRType(), retMatch); + if (retMatch.GetReg0() == kRinvalid) { + return; + } + + uint32 offset = 0; + std::vector result; + // load memOpnd to return reg + // ldr x0, [base] + // ldr x1, [base + 8] + auto generateReturnValToRegs = [this, &result, &offset, isRefField, &addrOpnd](regno_t regno, PrimType primType) { + bool isFpReg = IsPrimitiveFloat(primType) || IsPrimitiveVector(primType); + RegType regType = isFpReg ? kRegTyFloat : kRegTyInt; + if (CGOptions::IsBigEndian() && !isFpReg) { + primType = PTY_u64; + } else if (GetPrimTypeSize(primType) <= k4ByteSize) { + primType = isFpReg ? PTY_f32 : PTY_u32; + } + auto &phyReg = + GetOrCreatePhysicalRegisterOperand(static_cast(regno), GetPrimTypeBitSize(primType), regType); + DEBUG_ASSERT(addrOpnd->IsMemoryAccessOperand(), "NIY, must be mem opnd"); + auto *newMemOpnd = + &GetMemOperandAddOffset(static_cast(*addrOpnd), offset, GetPrimTypeBitSize(primType)); + MOperator ldMop = PickLdInsn(GetPrimTypeBitSize(primType), primType); + Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, phyReg, *newMemOpnd); + ldInsn.MarkAsAccessRefField(isRefField); + GetCurBB()->AppendInsn(ldInsn); + if (!VERIFY_INSN(&ldInsn)) { + SPLIT_INSN(&ldInsn, this); + } + + offset += GetPrimTypeSize(primType); + result.push_back(&phyReg); + }; + generateReturnValToRegs(retMatch.GetReg0(), retMatch.GetPrimTypeOfReg0()); + if (retMatch.GetReg1() != kRinvalid) { + generateReturnValToRegs(retMatch.GetReg1(), retMatch.GetPrimTypeOfReg1()); + } + if (retMatch.GetReg2() != kRinvalid) { + generateReturnValToRegs(retMatch.GetReg2(), retMatch.GetPrimTypeOfReg2()); + } + if (retMatch.GetReg3() != kRinvalid) { + generateReturnValToRegs(retMatch.GetReg3(), retMatch.GetPrimTypeOfReg3()); + } } Operand *AArch64CGFunc::SelectDread(const BaseNode &parent, DreadNode &expr) @@ -3063,7 +3028,7 @@ Operand *AArch64CGFunc::SelectDread(const BaseNode &parent, DreadNode &expr) /* use the second register return by __builtin_eh_return(). */ AArch64CallConvImpl retLocator(GetBecommon()); CCLocInfo retMech; - retLocator.InitReturnInfo(*type, retMech); + retLocator.LocateRetVal(*type, retMech); retLocator.SetupSecondRetReg(*type, retMech); return &GetOrCreatePhysicalRegisterOperand(static_cast(retMech.GetReg1()), k64BitSize, kRegTyInt); } @@ -3320,7 +3285,7 @@ Operand *AArch64CGFunc::SelectAddrof(AddrofNode &expr, const BaseNode &parent, b /* load the base address of the struct copy from stack. */ SelectAddrof(*stackAddr, CreateStImmOperand(*symbol, 0, 0)); Operand *structAddr; - if (GetBecommon().GetTypeSize(symbol->GetType()->GetTypeIndex().GetIdx()) <= k16ByteSize) { + if (!IsParamStructCopy(*symbol)) { isAggParamInReg = true; structAddr = stackAddr; } else { @@ -6788,7 +6753,7 @@ bool AArch64CGFunc::IsSaveReg(const RegOperand ®, MIRType &mirType, BECommon { CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind()); CCLocInfo retMechanism; - retLocator.InitReturnInfo(mirType, retMechanism); + retLocator.LocateRetVal(mirType, retMechanism); if (retMechanism.GetRegCount() > 0) { return reg.GetRegisterNumber() == retMechanism.GetReg0() || reg.GetRegisterNumber() == retMechanism.GetReg1() || reg.GetRegisterNumber() == retMechanism.GetReg2() || reg.GetRegisterNumber() == retMechanism.GetReg3(); @@ -7070,7 +7035,9 @@ void AArch64CGFunc::LmbcGenSaveSpForAlloca() return; } Operand &spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); - RegOperand &spSaveOpnd = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, GetPointerSize())); + regno_t regno = NewVReg(kRegTyInt, GetPointerSize()); + RegOperand &spSaveOpnd = CreateVirtualRegisterOperand(regno); + SetSpSaveReg(regno); Insn &save = GetInsnBuilder()->BuildInsn(MOP_xmovrr, spSaveOpnd, spOpnd); GetFirstBB()->AppendInsn(save); for (auto *retBB : GetExitBBsVec()) { @@ -7258,32 +7225,16 @@ void AArch64CGFunc::GenerateYieldpoint(BB &bb) bb.AppendInsn(yieldPoint); } -Operand &AArch64CGFunc::ProcessReturnReg(PrimType primType, int32 sReg) -{ - return GetTargetRetOperand(primType, sReg); -} - Operand &AArch64CGFunc::GetTargetRetOperand(PrimType primType, int32 sReg) { - uint32 bitSize = GetPrimTypeBitSize(primType) < k32BitSize ? k32BitSize : GetPrimTypeBitSize(primType); - AArch64reg pReg; - if (sReg < 0) { - return GetOrCreatePhysicalRegisterOperand(IsPrimitiveFloat(primType) || (IsPrimitiveVector(primType)) ? S0 : R0, - bitSize, GetRegTyFromPrimTy(primType)); - } else { - switch (sReg) { - case kSregRetval0: - pReg = IsPrimitiveFloat(primType) || (IsPrimitiveVector(primType)) ? S0 : R0; - break; - case kSregRetval1: - pReg = R1; - break; - default: - pReg = RLAST_INT_REG; - DEBUG_ASSERT(0, "GetTargetRetOperand: NYI"); - } - return GetOrCreatePhysicalRegisterOperand(pReg, bitSize, GetRegTyFromPrimTy(primType)); + DEBUG_ASSERT(!IsInt128Ty(primType), "NIY"); + if (IsSpecialPseudoRegister(-sReg)) { + return GetOrCreateSpecialRegisterOperand(sReg, primType); } + bool useFpReg = !IsPrimitiveInteger(primType) || IsPrimitiveVectorFloat(primType); + uint32 bitSize = GetPrimTypeBitSize(primType); + bitSize = bitSize <= k32BitSize ? k32BitSize : bitSize; + return GetOrCreatePhysicalRegisterOperand(useFpReg ? V0 : R0, bitSize, GetRegTyFromPrimTy(primType)); } RegOperand &AArch64CGFunc::CreateRegisterOperandOfType(PrimType primType) @@ -7514,8 +7465,8 @@ bool AArch64CGFunc::GenRetCleanup(const IntrinsiccallNode *cleanupNode, bool for if (minByteOffset < INT_MAX) { int32 refLocBase = memLayout->GetRefLocBaseLoc(); uint32 refNum = memLayout->GetSizeOfRefLocals() / kAarch64OffsetAlign; - CHECK_FATAL((refLocBase +(refNum - 1) * kAarch64IntregBytelen) < std::numeric_limits::max(), - "out of range"); + CHECK_FATAL((refLocBase + (refNum - 1) * kAarch64IntregBytelen) < std::numeric_limits::max(), + "out of range"); int32 refLocEnd = refLocBase + (refNum - 1) * kAarch64IntregBytelen; int32 realMin = minByteOffset < refLocBase ? refLocBase : minByteOffset; int32 realMax = maxByteOffset > refLocEnd ? refLocEnd : maxByteOffset; @@ -7724,9 +7675,8 @@ void AArch64CGFunc::HandleRCCall(bool begin, const MIRSymbol *retRef) ind++; } if (singleNum > 0) { - int32 offset = - memLayout->GetRefLocBaseLoc() + - kAarch64IntregBytelen * formalRef + kAarch64IntregBytelen * (refNum - 1); + int32 offset = memLayout->GetRefLocBaseLoc() + kAarch64IntregBytelen * formalRef + + kAarch64IntregBytelen * (refNum - 1); Operand &zeroOp = GetZeroOpnd(k64BitSize); Operand &stackLoc = CreateStkTopOpnd(static_cast(offset), GetPointerSize() * kBitsPerByte); Insn &setInc = GetInsnBuilder()->BuildInsn(MOP_xstr, zeroOp, stackLoc); @@ -7885,635 +7835,309 @@ void AArch64CGFunc::HandleRCCall(bool begin, const MIRSymbol *retRef) } } -void AArch64CGFunc::SelectParmListDreadSmallAggregate(const MIRSymbol &sym, MIRType &structType, ListOperand &srcOpnds, - int32 offset, AArch64CallConvImpl &parmLocator, FieldID fieldID) +void AArch64CGFunc::SelectLibMemCopy(RegOperand &destOpnd, RegOperand &srcOpnd, uint32 structSize) { - /* - * in two param regs if possible - * If struct is <= 8 bytes, then it fits into one param reg. - * If struct is <= 16 bytes, then it fits into two param regs. - * Otherwise, it goes onto the stack. - * If the number of available param reg is less than what is - * needed to fit the entire struct into them, then the param - * reg is skipped and the struct goes onto the stack. - * Example 1. - * struct size == 8 bytes. - * param regs x0 to x6 are used. - * struct is passed in x7. - * Example 2. - * struct is 16 bytes. - * param regs x0 to x5 are used. - * struct is passed in x6 and x7. - * Example 3. - * struct is 16 bytes. - * param regs x0 to x6 are used. x7 alone is not enough to pass the struct. - * struct is passed on the stack. - * x7 is not used, as the following param will go onto the stack also. - */ - int32 symSize = GetBecommon().GetTypeSize(structType.GetTypeIndex().GetIdx()); - CCLocInfo ploc; - parmLocator.LocateNextParm(structType, ploc); - if (ploc.reg0 == 0) { - /* No param regs available, pass on stack. */ - /* If symSize is <= 8 bytes then use 1 reg, else 2 */ - CreateCallStructParamPassByStack(symSize, &sym, nullptr, ploc.memOffset); - } else { - /* pass by param regs. */ - RegOperand *parmOpnd0 = SelectParmListDreadAccessField(sym, fieldID, ploc, offset, 0); - srcOpnds.PushOpnd(*parmOpnd0); - if (ploc.reg1) { - RegOperand *parmOpnd1 = SelectParmListDreadAccessField(sym, fieldID, ploc, offset, 1); - srcOpnds.PushOpnd(*parmOpnd1); - } - if (ploc.reg2) { - RegOperand *parmOpnd2 = SelectParmListDreadAccessField(sym, fieldID, ploc, offset, 2); - srcOpnds.PushOpnd(*parmOpnd2); - } - if (ploc.reg3) { - RegOperand *parmOpnd3 = SelectParmListDreadAccessField(sym, fieldID, ploc, offset, 3); - srcOpnds.PushOpnd(*parmOpnd3); - } - } + std::vector opndVec; + opndVec.push_back(&CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize))); // result + opndVec.push_back(&destOpnd); // param 0 + opndVec.push_back(&srcOpnd); // param 1 + opndVec.push_back(&CreateImmOperand(structSize, k64BitSize, false)); // param 2 + SelectLibCall("memcpy", opndVec, PTY_a64, PTY_a64); } -void AArch64CGFunc::SelectParmListIreadSmallAggregate(const IreadNode &iread, MIRType &structType, - ListOperand &srcOpnds, int32 offset, - AArch64CallConvImpl &parmLocator) +void AArch64CGFunc::SelectInsnMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size, + bool isRefField, BaseNode *destNode, BaseNode *srcNode) { - int32 symSize = GetBecommon().GetTypeSize(structType.GetTypeIndex().GetIdx()); - RegOperand *addrOpnd0 = static_cast(HandleExpr(iread, *(iread.Opnd(0)))); - RegOperand *addrOpnd1 = &LoadIntoRegister(*addrOpnd0, iread.Opnd(0)->GetPrimType()); - CCLocInfo ploc; - parmLocator.LocateNextParm(structType, ploc); - if (ploc.reg0 == 0) { - /* No param regs available, pass on stack. */ - CreateCallStructParamPassByStack(symSize, nullptr, addrOpnd1, ploc.memOffset); - } else { - /* pass by param regs. */ - fpParamState state = kStateUnknown; - uint32 memSize = 0; - switch (ploc.fpSize) { - case k0BitSize: - state = kNotFp; - memSize = k64BitSize; - break; - case k4BitSize: - state = kFp32Bit; - memSize = k32BitSize; - break; - case k8BitSize: - state = kFp64Bit; - memSize = k64BitSize; - break; - default: - break; - } - OfstOperand *offOpnd0 = &GetOrCreateOfstOpnd(static_cast(static_cast(offset)), k32BitSize); - MemOperand *mopnd = - &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, memSize, addrOpnd1, nullptr, offOpnd0, nullptr); - CreateCallStructParamPassByReg(ploc.reg0, *mopnd, srcOpnds, state); - if (ploc.reg1) { - OfstOperand *offOpnd1 = &GetOrCreateOfstOpnd( - ((ploc.fpSize ? ploc.fpSize : GetPointerSize()) + static_cast(offset)), k32BitSize); - mopnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, memSize, addrOpnd1, nullptr, offOpnd1, nullptr); - CreateCallStructParamPassByReg(ploc.reg1, *mopnd, srcOpnds, state); - } - if (ploc.reg2) { - OfstOperand *offOpnd2 = &GetOrCreateOfstOpnd( - ((ploc.fpSize ? (ploc.fpSize * k4BitShift) : GetPointerSize()) + static_cast(offset)), - k32BitSize); - mopnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, memSize, addrOpnd1, nullptr, offOpnd2, nullptr); - CreateCallStructParamPassByReg(ploc.reg2, *mopnd, srcOpnds, state); - } - if (ploc.reg3) { - OfstOperand *offOpnd3 = &GetOrCreateOfstOpnd( - ((ploc.fpSize ? (ploc.fpSize * k8BitShift) : GetPointerSize()) + static_cast(offset)), - k32BitSize); - mopnd = &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, memSize, addrOpnd1, nullptr, offOpnd3, nullptr); - CreateCallStructParamPassByReg(ploc.reg3, *mopnd, srcOpnds, state); + auto createMemCopy = [this, isRefField, destNode, srcNode](MemOperand &dest, MemOperand &src, uint32 byteSize) { + Insn *ldInsn = nullptr; + Insn *stInsn = nullptr; + + if (byteSize == k16ByteSize) { // ldp/stp + auto &tmpOpnd1 = CreateRegisterOperandOfType(PTY_u64); + auto &tmpOpnd2 = CreateRegisterOperandOfType(PTY_u64); + // ldr srcMem to tmpReg + ldInsn = &GetInsnBuilder()->BuildInsn(MOP_xldp, tmpOpnd1, tmpOpnd2, src); + // str tempReg to destMem + stInsn = &GetInsnBuilder()->BuildInsn(MOP_xstp, tmpOpnd1, tmpOpnd2, dest); + } else { + PrimType primType = + (byteSize == k8ByteSize) + ? PTY_u64 + : (byteSize == k4ByteSize) + ? PTY_u32 + : (byteSize == k2ByteSize) ? PTY_u16 : (byteSize == k1ByteSize) ? PTY_u8 : PTY_unknown; + DEBUG_ASSERT(primType != PTY_unknown, "NIY, unkown byte size"); + auto &tmpOpnd = CreateRegisterOperandOfType(kRegTyInt, byteSize); + // ldr srcMem to tmpReg + ldInsn = &GetInsnBuilder()->BuildInsn(PickLdInsn(byteSize * kBitsPerByte, primType), tmpOpnd, src); + // str tempReg to destMem + stInsn = &GetInsnBuilder()->BuildInsn(PickStInsn(byteSize * kBitsPerByte, primType), tmpOpnd, dest); + } + // Set memory reference info + SetMemReferenceOfInsn(*ldInsn, srcNode); + ldInsn->MarkAsAccessRefField(isRefField); + GetCurBB()->AppendInsn(*ldInsn); + if (!VERIFY_INSN(ldInsn)) { + SPLIT_INSN(ldInsn, this); + } + + // Set memory reference info + SetMemReferenceOfInsn(*stInsn, destNode); + GetCurBB()->AppendInsn(*stInsn); + if (!VERIFY_INSN(stInsn)) { + SPLIT_INSN(stInsn, this); + } + }; + + // Insn can be reduced when sizeNotCoverd = 3 | 5 | 6 | 7 + for (uint32 offset = 0; offset < size;) { + auto sizeNotCoverd = size - offset; + uint32 copyByteSize = 0; + if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && + srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && + sizeNotCoverd >= k16ByteSize) { // ldp/stp unsupport lo12li mem + copyByteSize = k16ByteSize; + } else if (sizeNotCoverd >= k8ByteSize) { + copyByteSize = k8ByteSize; + } else if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && + srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && sizeNotCoverd > k4ByteSize && + offset >= k8ByteSize - sizeNotCoverd) { + copyByteSize = k8ByteSize; // 5: w + b -> x ; 6: w + h -> x ; 7: w + h + b -> x + offset -= (k8ByteSize - sizeNotCoverd); + } else if (sizeNotCoverd >= k4ByteSize) { + copyByteSize = k4ByteSize; + } else if (destOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && + srcOpnd.GetAddrMode() != MemOperand::kAddrModeLo12Li && sizeNotCoverd > k2ByteSize && + offset >= k4ByteSize - sizeNotCoverd) { + copyByteSize = k4ByteSize; // 3: h + b -> w + offset -= (k4ByteSize - sizeNotCoverd); + } else if (sizeNotCoverd >= k2ByteSize) { + copyByteSize = k2ByteSize; + } else { + copyByteSize = k1ByteSize; } - } -} -void AArch64CGFunc::SelectParmListDreadLargeAggregate(const MIRSymbol &sym, MIRType &structType, ListOperand &srcOpnds, - AArch64CallConvImpl &parmLocator, int32 &structCopyOffset, - int32 fromOffset) -{ - /* - * Pass larger sized struct on stack. - * Need to copy the entire structure onto the stack. - * The pointer to the starting address of the copied struct is then - * used as the parameter for the struct. - * This pointer is passed as the next parameter. - * Example 1: - * struct is 23 bytes. - * param regs x0 to x5 are used. - * First around up 23 to 24, so 3 of 8-byte slots. - * Copy struct to a created space on the stack. - * Pointer of copied struct is passed in x6. - * Example 2: - * struct is 25 bytes. - * param regs x0 to x7 are used. - * First around up 25 to 32, so 4 of 8-byte slots. - * Copy struct to a created space on the stack. - * Pointer of copied struct is passed on stack as the 9th parameter. - */ - uint64 symSize = GetBecommon().GetTypeSize(structType.GetTypeIndex().GetIdx()); - CCLocInfo ploc; - parmLocator.LocateNextParm(structType, ploc); - uint32 numMemOp = static_cast(RoundUp(symSize, GetPointerSize()) / GetPointerSize()); /* round up */ - /* Create the struct copies. */ - RegOperand *parmOpnd = - CreateCallStructParamCopyToStack(numMemOp, &sym, nullptr, structCopyOffset, fromOffset, ploc); - if (parmOpnd) { - srcOpnds.PushOpnd(*parmOpnd); - } - structCopyOffset += static_cast(numMemOp * GetPointerSize()); -} + auto &srcMem = GetMemOperandAddOffset(srcOpnd, offset, copyByteSize * kBitsPerByte); + auto &destMem = GetMemOperandAddOffset(destOpnd, offset, copyByteSize * kBitsPerByte); + createMemCopy(destMem, srcMem, copyByteSize); -void AArch64CGFunc::SelectParmListIreadLargeAggregate(const IreadNode &iread, MIRType &structType, - ListOperand &srcOpnds, AArch64CallConvImpl &parmLocator, - int32 &structCopyOffset, int32 fromOffset) -{ - uint64 symSize = GetBecommon().GetTypeSize(structType.GetTypeIndex().GetIdx()); - RegOperand *addrOpnd0 = static_cast(HandleExpr(iread, *(iread.Opnd(0)))); - RegOperand *addrOpnd1 = &LoadIntoRegister(*addrOpnd0, iread.Opnd(0)->GetPrimType()); - CCLocInfo ploc; - parmLocator.LocateNextParm(structType, ploc); - uint32 numMemOp = static_cast(RoundUp(symSize, GetPointerSize()) / GetPointerSize()); /* round up */ - RegOperand *parmOpnd = - CreateCallStructParamCopyToStack(numMemOp, nullptr, addrOpnd1, structCopyOffset, fromOffset, ploc); - structCopyOffset += static_cast(numMemOp * GetPointerSize()); - if (parmOpnd) { - srcOpnds.PushOpnd(*parmOpnd); + offset += copyByteSize; } } -void AArch64CGFunc::CreateCallStructParamPassByStack(int32 symSize, const MIRSymbol *sym, RegOperand *addrOpnd, - int32 baseOffset) +void AArch64CGFunc::SelectMemCopy(const MemOperand &destOpnd, const MemOperand &srcOpnd, uint32 size, bool isRefField, + BaseNode *destNode, BaseNode *srcNode) { - if (symSize == 0) { + if (size > kParmMemcpySize) { + SelectLibMemCopy(*ExtractMemBaseAddr(destOpnd), *ExtractMemBaseAddr(srcOpnd), size); return; } - MemOperand *ldMopnd = nullptr; - MemOperand *stMopnd = nullptr; - uint32 numRegNeeded = (static_cast(symSize) <= k8ByteSize) ? kOneRegister : kTwoRegister; - for (int j = 0; j < static_cast(numRegNeeded); j++) { - if (sym) { - if (CGOptions::IsArm64ilp32()) { - ldMopnd = &GetOrCreateMemOpnd(*sym, (j * static_cast(k8ByteSize)), k64BitSize); - } else { - ldMopnd = &GetOrCreateMemOpnd(*sym, (j * static_cast(GetPointerSize())), k64BitSize); - } - } else { - if (CGOptions::IsArm64ilp32()) { - ldMopnd = - &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, addrOpnd, nullptr, - &GetOrCreateOfstOpnd(static_cast(j) * k8ByteSize, k32BitSize), nullptr); - } else { - ldMopnd = &GetOrCreateMemOpnd( - MemOperand::kAddrModeBOi, k64BitSize, addrOpnd, nullptr, - &GetOrCreateOfstOpnd(static_cast(j) * GetPointerSize(), k32BitSize), nullptr); - } - } - RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *ldMopnd)); - if (CGOptions::IsArm64ilp32()) { - stMopnd = - &CreateMemOpnd(RSP, (static_cast(baseOffset) + (j * static_cast(k8ByteSize))), k64BitSize); - } else { - stMopnd = &CreateMemOpnd(RSP, (static_cast(baseOffset) + (j * GetPointerSize())), k64BitSize); - } - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(k64BitSize, PTY_i64), *vreg, *stMopnd)); - } + SelectInsnMemCopy(destOpnd, srcOpnd, size, isRefField, destNode, srcNode); } -RegOperand *AArch64CGFunc::SelectParmListDreadAccessField(const MIRSymbol &sym, FieldID fieldID, const CCLocInfo &ploc, - int32 offset, uint32 parmNum) +void AArch64CGFunc::SelectParmListPreprocessForAggregate(BaseNode &argExpr, int32 &structCopyOffset, + std::vector &argsDesc, bool isArgUnused) { - uint32 memSize; - PrimType primType; - RegOperand *parmOpnd; - uint32 dataSizeBits; - AArch64reg reg; - switch (parmNum) { - case 0: - reg = static_cast(ploc.reg0); - break; - case 1: - reg = static_cast(ploc.reg1); - break; - case 2: // parmNum 2 use reg2 - reg = static_cast(ploc.reg2); - break; - case 3: // parmNum 3 use reg3 - reg = static_cast(ploc.reg3); - break; - default: - CHECK_FATAL(false, "Exceeded maximum allowed fp parameter registers for struct passing"); - } - if (ploc.fpSize == 0) { - memSize = k64BitSize; - primType = PTY_i64; - dataSizeBits = GetPrimTypeSize(PTY_i64) * kBitsPerByte; - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k64BitSize, kRegTyInt); - } else if (ploc.fpSize == k4ByteSize) { - memSize = k32BitSize; - primType = PTY_f32; - dataSizeBits = GetPrimTypeSize(PTY_f32) * kBitsPerByte; - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k32BitSize, kRegTyFloat); - } else if (ploc.fpSize == k8ByteSize) { - memSize = k64BitSize; - primType = PTY_f64; - dataSizeBits = GetPrimTypeSize(PTY_i64) * kBitsPerByte; - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k64BitSize, kRegTyFloat); - } else { - CHECK_FATAL(false, "Unknown call parameter state"); - } - MemOperand *memOpnd; - if (sym.GetStorageClass() == kScFormal && fieldID > 0) { - MIRType *ty = sym.GetType(); - uint64 symSize = GetBecommon().GetTypeSize(ty->GetTypeIndex().GetIdx()); - /* sym passed by address, need to be dereference */ - if (symSize > k16ByteSize) { - MemOperand &baseOpnd = GetOrCreateMemOpnd(sym, 0, memSize); - RegOperand &base = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), base, baseOpnd)); - memOpnd = &CreateMemOpnd(base, (static_cast(offset) + parmNum * GetPointerSize()), memSize); - } else { /* sym passed by register , no need to be dereference */ - if (CGOptions::IsArm64ilp32()) { - memOpnd = &GetOrCreateMemOpnd(sym, (k8ByteSize * parmNum + static_cast(offset)), memSize); - } else { - memOpnd = &GetOrCreateMemOpnd(sym, (GetPointerSize() * parmNum + static_cast(offset)), memSize); - } - } - } else if (ploc.fpSize) { - memOpnd = &GetOrCreateMemOpnd(sym, (ploc.fpSize * parmNum + static_cast(offset)), memSize); - } else { - if (CGOptions::IsArm64ilp32()) { - memOpnd = &GetOrCreateMemOpnd(sym, (k8ByteSize * parmNum + static_cast(offset)), memSize); - } else { - memOpnd = &GetOrCreateMemOpnd(sym, (GetPointerSize() * parmNum + static_cast(offset)), memSize); - } + MemRWNodeHelper memHelper(argExpr, GetFunction(), GetBecommon()); + auto mirSize = memHelper.GetMemSize(); + if (mirSize <= k16BitSize) { + argsDesc.emplace_back(memHelper.GetMIRType(), &argExpr, memHelper.GetByteOffset()); + return; } - MOperator selectedMop = PickLdInsn(dataSizeBits, primType); - if ((memOpnd->GetAddrMode() == MemOperand::kAddrModeBOi) && - !IsOperandImmValid(selectedMop, memOpnd, kInsnSecondOpnd)) { - memOpnd = &SplitOffsetWithAddInstruction(*memOpnd, dataSizeBits); + + PrimType baseType = PTY_begin; + size_t elemNum = 0; + if (IsHomogeneousAggregates(*memHelper.GetMIRType(), baseType, elemNum)) { + // B.3 If the argument type is an HFA or an HVA, then the argument is used unmodified. + argsDesc.emplace_back(memHelper.GetMIRType(), &argExpr, memHelper.GetByteOffset()); + return; } - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(selectedMop, *parmOpnd, *memOpnd)); - return parmOpnd; -} + // B.4 If the argument type is a Composite Type that is larger than 16 bytes, + // then the argument is copied to memory allocated by the caller + // and the argument is replaced by a pointer to the copy. + structCopyOffset = static_cast(RoundUp(static_cast(structCopyOffset), k8ByteSize)); -void AArch64CGFunc::CreateCallStructParamPassByReg(regno_t regno, MemOperand &memOpnd, ListOperand &srcOpnds, - fpParamState state) -{ - RegOperand *parmOpnd; - uint32 dataSizeBits = 0; - PrimType pType = PTY_void; - parmOpnd = nullptr; - AArch64reg reg = static_cast(regno); - if (state == kNotFp) { - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k64BitSize, kRegTyInt); - dataSizeBits = GetPrimTypeSize(PTY_i64) * kBitsPerByte; - pType = PTY_i64; - } else if (state == kFp32Bit) { - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k32BitSize, kRegTyFloat); - dataSizeBits = GetPrimTypeSize(PTY_f32) * kBitsPerByte; - pType = PTY_f32; - } else if (state == kFp64Bit) { - parmOpnd = &GetOrCreatePhysicalRegisterOperand(reg, k64BitSize, kRegTyFloat); - dataSizeBits = GetPrimTypeSize(PTY_f64) * kBitsPerByte; - pType = PTY_f64; - } else { - DEBUG_ASSERT(0, "CreateCallStructParamPassByReg: Unknown state"); - } + // pre copy + auto *rhsMemOpnd = SelectRhsMemOpnd(argExpr); + if (!isArgUnused) { + auto &spReg = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); + auto &offsetOpnd = CreateImmOperand(structCopyOffset, k64BitSize, false); + auto *destMemOpnd = CreateMemOperand(k64BitSize, spReg, offsetOpnd, false); - MOperator selectedMop = PickLdInsn(dataSizeBits, pType); - if (!IsOperandImmValid(selectedMop, &memOpnd, kInsnSecondOpnd)) { - memOpnd = SplitOffsetWithAddInstruction(memOpnd, dataSizeBits); + auto copySize = CGOptions::IsBigEndian() ? static_cast(RoundUp(mirSize, k8ByteSize)) : mirSize; + SelectMemCopy(*destMemOpnd, *rhsMemOpnd, copySize); } - DEBUG_ASSERT(parmOpnd != nullptr, "parmOpnd should not be nullptr"); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(selectedMop, *parmOpnd, memOpnd)); - srcOpnds.PushOpnd(*parmOpnd); + + (void)argsDesc.emplace_back(memHelper.GetMIRType(), nullptr, static_cast(structCopyOffset), true); + structCopyOffset += static_cast(RoundUp(mirSize, k8ByteSize)); } -void AArch64CGFunc::CreateCallStructParamMemcpy(const MIRSymbol &sym, uint32 structSize, int32 copyOffset, - int32 fromOffset) +// Stage B - Pre-padding and extension of arguments +bool AArch64CGFunc::SelectParmListPreprocess(StmtNode &naryNode, size_t start, std::vector &argsDesc, + const MIRFunction *callee) { - std::vector opndVec; - - RegOperand *vreg1 = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - opndVec.push_back(vreg1); /* result */ - - RegOperand *parmOpnd = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - RegOperand *spReg = &GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); - ImmOperand *offsetOpnd0 = &CreateImmOperand(copyOffset, k64BitSize, false); - SelectAdd(*parmOpnd, *spReg, *offsetOpnd0, PTY_a64); - opndVec.push_back(parmOpnd); /* param 0 */ - - if (sym.GetStorageClass() == kScGlobal || sym.GetStorageClass() == kScExtern) { - StImmOperand &stopnd = CreateStImmOperand(sym, fromOffset, 0); - RegOperand &staddropnd = static_cast(CreateRegisterOperandOfType(PTY_u64)); - SelectAddrof(staddropnd, stopnd); - opndVec.push_back(&staddropnd); /* param 1 */ - } else if (sym.GetStorageClass() == kScAuto || sym.GetStorageClass() == kScFormal) { - RegOperand *parm1Reg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - AArch64SymbolAlloc *symloc = - static_cast(GetMemlayout()->GetSymAllocInfo(sym.GetStIndex())); - RegOperand *baseOpnd = static_cast(GetBaseReg(*symloc)); - int32 stoffset = GetBaseOffset(*symloc); - ImmOperand *offsetOpnd1 = &CreateImmOperand(static_cast(stoffset), k64BitSize, false); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *parm1Reg, *baseOpnd, *offsetOpnd1)); - if (sym.GetStorageClass() == kScFormal) { - MemOperand *ldmopnd = - &GetOrCreateMemOpnd(MemOperand::kAddrModeBOi, k64BitSize, parm1Reg, nullptr, - &GetOrCreateOfstOpnd(0, k32BitSize), static_cast(nullptr)); - RegOperand *tmpreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - RegOperand *vreg2 = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_a64), *tmpreg, *ldmopnd)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *vreg2, *tmpreg, - CreateImmOperand(fromOffset, k64BitSize, false))); - parm1Reg = vreg2; - } - opndVec.push_back(parm1Reg); /* param 1 */ - } else if (sym.GetStorageClass() == kScPstatic || sym.GetStorageClass() == kScFstatic) { - CHECK_FATAL(sym.GetSKind() != kStConst, "Unsupported sym const for struct param"); - StImmOperand *stopnd = &CreateStImmOperand(sym, 0, 0); - RegOperand &staddropnd = static_cast(CreateRegisterOperandOfType(PTY_u64)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrp, staddropnd, *stopnd)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xadrpl12, staddropnd, staddropnd, *stopnd)); - opndVec.push_back(&staddropnd); /* param 1 */ - } else { - CHECK_FATAL(false, "Unsupported sym for struct param"); - } - - RegOperand &vreg3 = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - ImmOperand &sizeOpnd = CreateImmOperand(structSize, k64BitSize, false); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, vreg3, sizeOpnd)); - opndVec.push_back(&vreg3); /* param 2 */ + bool hasSpecialArg = false; + int32 structCopyOffset = GetMaxParamStackSize() - GetStructCopySize(); + for (size_t i = start; i < naryNode.NumOpnds(); ++i) { + BaseNode *argExpr = naryNode.Opnd(i); + DEBUG_ASSERT(argExpr != nullptr, "not null check"); + PrimType primType = argExpr->GetPrimType(); + DEBUG_ASSERT(primType != PTY_void, "primType should not be void"); + if (primType == PTY_agg) { + SelectParmListPreprocessForAggregate(*argExpr, structCopyOffset, argsDesc, + (callee && callee->GetFuncDesc().IsArgUnused(i))); + } else { + auto *mirType = GlobalTables::GetTypeTable().GetPrimType(primType); + (void)argsDesc.emplace_back(mirType, argExpr); + } - SelectLibCall("memcpy", opndVec, PTY_a64, PTY_a64); + if (MarkParmListCall(*argExpr)) { + argsDesc.rbegin()->isSpecialArg = true; + hasSpecialArg = true; + } + } + return hasSpecialArg; } -void AArch64CGFunc::CreateCallStructParamMemcpy(RegOperand &addrOpnd, uint32 structSize, int32 copyOffset, - int32 fromOffset) +std::pair AArch64CGFunc::GetCalleeFunction(StmtNode &naryNode) const { - std::vector opndVec; - - RegOperand *vreg1 = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - opndVec.push_back(vreg1); /* result */ - - RegOperand *parmOpnd = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - RegOperand *spReg = &GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); - ImmOperand *offsetOpnd0 = &CreateImmOperand(copyOffset, k64BitSize, false); - SelectAdd(*parmOpnd, *spReg, *offsetOpnd0, PTY_a64); - opndVec.push_back(parmOpnd); /* param 0 */ - - if (fromOffset) { - RegOperand &p1vreg = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - ImmOperand &fromImm = CreateImmOperand(fromOffset, k64BitSize, true); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, p1vreg, addrOpnd, fromImm)); - opndVec.push_back(&p1vreg); /* param 1 */ - } else { - opndVec.push_back(&addrOpnd); /* param 1 */ + MIRFunction *callee = nullptr; + MIRFuncType *calleeType = nullptr; + if (dynamic_cast(&naryNode) != nullptr) { + auto calleePuIdx = static_cast(naryNode).GetPUIdx(); + callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(calleePuIdx); + calleeType = callee->GetMIRFuncType(); + } else if (naryNode.GetOpCode() == OP_icallproto) { + auto *iCallNode = &static_cast(naryNode); + MIRType *protoType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iCallNode->GetRetTyIdx()); + if (protoType->IsMIRPtrType()) { + calleeType = static_cast(protoType)->GetPointedFuncType(); + } else if (protoType->IsMIRFuncType()) { + calleeType = static_cast(protoType); + } } - - RegOperand &vreg3 = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8BitSize)); - ImmOperand &sizeOpnd = CreateImmOperand(structSize, k64BitSize, false); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_wmovri32, vreg3, sizeOpnd)); - opndVec.push_back(&vreg3); /* param 2 */ - - SelectLibCall("memcpy", opndVec, PTY_a64, PTY_a64); + return {callee, calleeType}; } -RegOperand *AArch64CGFunc::CreateCallStructParamCopyToStack(uint32 numMemOp, const MIRSymbol *sym, RegOperand *addrOpd, - int32 copyOffset, int32 fromOffset, const CCLocInfo &ploc) +void AArch64CGFunc::SelectParmListSmallStruct(const MIRType &mirType, const CCLocInfo &ploc, Operand &addr, + ListOperand &srcOpnds, bool isSpecialArg, + std::vector ®MapForTmpBB) { - /* Create the struct copies. */ - MemOperand *ldMopnd = nullptr; - MemOperand *stMopnd = nullptr; - for (uint32 j = 0; j < numMemOp; j++) { - if (sym != nullptr) { - if (sym->GetStorageClass() == kScFormal) { - MemOperand &base = GetOrCreateMemOpnd(*sym, 0, k64BitSize); - RegOperand &vreg = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - Insn &ldInsn = GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), vreg, base); + uint32 offset = 0; + DEBUG_ASSERT(addr.IsMemoryAccessOperand(), "NIY, must be mem opnd"); + uint64 size = mirType.GetSize(); + auto &memOpnd = static_cast(addr); + // ldr memOpnd to parmReg + auto loadParamFromMem = [this, &offset, &memOpnd, &srcOpnds, &size, isSpecialArg, + ®MapForTmpBB](AArch64reg regno, PrimType primType) { + auto &phyReg = + GetOrCreatePhysicalRegisterOperand(regno, GetPrimTypeBitSize(primType), GetRegTyFromPrimTy(primType)); + bool isFpReg = !IsPrimitiveInteger(primType) || IsPrimitiveVectorFloat(primType); + if (!CGOptions::IsBigEndian() && !isFpReg && (size - offset < k8ByteSize)) { + // load exact size agg (BigEndian not support yet) + RegOperand *valOpnd = nullptr; + for (uint32 exactOfst = 0; exactOfst < (size - offset);) { + PrimType exactPrimType; + auto loadSize = size - offset - exactOfst; + if (loadSize >= k4ByteSize) { + exactPrimType = PTY_u32; + } else if (loadSize >= k2ByteSize) { + exactPrimType = PTY_u16; + } else { + exactPrimType = PTY_u8; + } + auto ldBitSize = GetPrimTypeBitSize(exactPrimType); + auto *ldOpnd = &GetMemOperandAddOffset(memOpnd, exactOfst + offset, ldBitSize); + auto ldMop = PickLdInsn(ldBitSize, exactPrimType); + auto &tmpValOpnd = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, GetPrimTypeSize(exactPrimType))); + Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, tmpValOpnd, *ldOpnd); GetCurBB()->AppendInsn(ldInsn); - ldMopnd = &GetOrCreateMemOpnd( - MemOperand::kAddrModeBOi, k64BitSize, &vreg, nullptr, - &GetOrCreateOfstOpnd((j * GetPointerSize() + static_cast(fromOffset)), k32BitSize), - nullptr); - } else { - if (CGOptions::IsArm64ilp32()) { - ldMopnd = - &GetOrCreateMemOpnd(*sym, (j * GetPointerSize() + static_cast(fromOffset)), k32BitSize); + if (!VERIFY_INSN(&ldInsn)) { + SPLIT_INSN(&ldInsn, this); + } + + if (exactOfst != 0) { + auto &shiftOpnd = CreateImmOperand(exactOfst * kBitsPerByte, k32BitSize, false); + SelectShift(tmpValOpnd, tmpValOpnd, shiftOpnd, kShiftLeft, primType); + } + if (valOpnd) { + SelectBior(*valOpnd, *valOpnd, tmpValOpnd, primType); } else { - ldMopnd = - &GetOrCreateMemOpnd(*sym, (j * GetPointerSize() + static_cast(fromOffset)), k64BitSize); + valOpnd = &tmpValOpnd; } + exactOfst += GetPrimTypeSize(exactPrimType); + } + if (isSpecialArg) { + regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&phyReg, primType, valOpnd, primType)); + } else { + SelectCopy(phyReg, primType, *valOpnd, primType); } } else { - ldMopnd = &GetOrCreateMemOpnd( - MemOperand::kAddrModeBOi, k64BitSize, addrOpd, nullptr, - &GetOrCreateOfstOpnd((j * GetPointerSize() + static_cast(fromOffset)), k32BitSize), nullptr); - } - if (CGOptions::IsArm64ilp32()) { - RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k4ByteSize)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k32BitSize, PTY_i32), *vreg, *ldMopnd)); - - stMopnd = &CreateMemOpnd(RSP, (static_cast(copyOffset) + (j * GetPointerSize())), k32BitSize); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(k32BitSize, PTY_i32), *vreg, *stMopnd)); - } else { - RegOperand *vreg = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickLdInsn(k64BitSize, PTY_i64), *vreg, *ldMopnd)); - - stMopnd = &CreateMemOpnd(RSP, (static_cast(copyOffset) + (j * GetPointerSize())), k64BitSize); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(k64BitSize, PTY_i64), *vreg, *stMopnd)); + auto *ldOpnd = &GetMemOperandAddOffset(memOpnd, offset, GetPrimTypeBitSize(primType)); + auto ldMop = PickLdInsn(GetPrimTypeBitSize(primType), primType); + if (isSpecialArg) { + RegOperand *tmpReg = &CreateRegisterOperandOfType(primType); + Insn &tmpLdInsn = GetInsnBuilder()->BuildInsn(ldMop, *tmpReg, *ldOpnd); + regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&phyReg, primType, tmpReg, primType)); + GetCurBB()->AppendInsn(tmpLdInsn); + if (!VERIFY_INSN(&tmpLdInsn)) { + SPLIT_INSN(&tmpLdInsn, this); + } + } else { + Insn &ldInsn = GetInsnBuilder()->BuildInsn(ldMop, phyReg, *ldOpnd); + GetCurBB()->AppendInsn(ldInsn); + if (!VERIFY_INSN(&ldInsn)) { + SPLIT_INSN(&ldInsn, this); + } + } } + srcOpnds.PushOpnd(phyReg); + offset += GetPrimTypeSize(primType); + }; + loadParamFromMem(static_cast(ploc.reg0), ploc.primTypeOfReg0); + if (ploc.reg1 != kRinvalid) { + loadParamFromMem(static_cast(ploc.reg1), ploc.primTypeOfReg1); } - /* Create the copy address parameter for the struct */ - RegOperand *fpopnd = &GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); - ImmOperand *offset = &CreateImmOperand(copyOffset, k64BitSize, false); - if (ploc.reg0 == kRinvalid) { - RegOperand &res = CreateRegisterOperandOfType(PTY_u64); - SelectAdd(res, *fpopnd, *offset, PTY_u64); - MemOperand &stMopnd2 = CreateMemOpnd(RSP, ploc.memOffset, k64BitSize); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(k64BitSize, PTY_i64), res, stMopnd2)); - return nullptr; - } else { - RegOperand *parmOpnd = - &GetOrCreatePhysicalRegisterOperand(static_cast(ploc.reg0), k64BitSize, kRegTyInt); - SelectAdd(*parmOpnd, *fpopnd, *offset, PTY_a64); - return parmOpnd; + if (ploc.reg2 != kRinvalid) { + loadParamFromMem(static_cast(ploc.reg2), ploc.primTypeOfReg2); + } + if (ploc.reg3 != kRinvalid) { + loadParamFromMem(static_cast(ploc.reg3), ploc.primTypeOfReg3); } } -void AArch64CGFunc::CreateCallStructMemcpyToParamReg(MIRType &structType, int32 structCopyOffset, - AArch64CallConvImpl &parmLocator, ListOperand &srcOpnds) +void AArch64CGFunc::SelectParmListPassByStack(const MIRType &mirType, Operand &opnd, uint32 memOffset, bool preCopyed, + std::vector &insnForStackArgs) { - RegOperand &spReg = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); - ImmOperand &offsetOpnd = CreateImmOperand(structCopyOffset, k64BitSize, false); - - CCLocInfo ploc; - parmLocator.LocateNextParm(structType, ploc); - if (ploc.reg0 != 0) { - RegOperand &res = GetOrCreatePhysicalRegisterOperand(static_cast(ploc.reg0), k64BitSize, kRegTyInt); - SelectAdd(res, spReg, offsetOpnd, PTY_a64); - srcOpnds.PushOpnd(res); - } else { - RegOperand &parmOpnd = CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); - SelectAdd(parmOpnd, spReg, offsetOpnd, PTY_a64); - MemOperand &stmopnd = CreateMemOpnd(RSP, ploc.memOffset, k64BitSize); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(PickStInsn(k64BitSize, PTY_i64), parmOpnd, stmopnd)); - } -} - -void AArch64CGFunc::SelectParmListForAggregate(BaseNode &argExpr, ListOperand &srcOpnds, - AArch64CallConvImpl &parmLocator, int32 &structCopyOffset) -{ - uint64 symSize; - int32 rhsOffset = 0; - if (argExpr.GetOpCode() == OP_dread) { - DreadNode &dread = static_cast(argExpr); - MIRSymbol *sym = GetBecommon().GetMIRModule().CurFunction()->GetLocalOrGlobalSymbol(dread.GetStIdx()); - MIRType *ty = sym->GetType(); - if (dread.GetFieldID() != 0) { - MIRStructType *structty = static_cast(ty); - ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(structty->GetFieldTyIdx(dread.GetFieldID())); - rhsOffset = GetBecommon().GetFieldOffset(*structty, dread.GetFieldID()).first; - } - symSize = GetBecommon().GetTypeSize(ty->GetTypeIndex().GetIdx()); - if (symSize <= k16ByteSize) { - SelectParmListDreadSmallAggregate(*sym, *ty, srcOpnds, rhsOffset, parmLocator, dread.GetFieldID()); - } else if (symSize > kParmMemcpySize) { - CreateCallStructMemcpyToParamReg(*ty, structCopyOffset, parmLocator, srcOpnds); - structCopyOffset += static_cast(RoundUp(symSize, GetPointerSize())); - } else { - SelectParmListDreadLargeAggregate(*sym, *ty, srcOpnds, parmLocator, structCopyOffset, rhsOffset); - } - } else if (argExpr.GetOpCode() == OP_iread) { - IreadNode &iread = static_cast(argExpr); - MIRPtrType *pointerty = - static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread.GetTyIdx())); - MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->GetPointedTyIdx()); - if (iread.GetFieldID() != 0) { - MIRStructType *structty = static_cast(ty); - ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(structty->GetFieldTyIdx(iread.GetFieldID())); - rhsOffset = GetBecommon().GetFieldOffset(*structty, iread.GetFieldID()).first; - } - symSize = GetBecommon().GetTypeSize(ty->GetTypeIndex().GetIdx()); - if (symSize <= k16ByteSize) { - SelectParmListIreadSmallAggregate(iread, *ty, srcOpnds, rhsOffset, parmLocator); - } else if (symSize > kParmMemcpySize) { - RegOperand *ireadOpnd = static_cast(HandleExpr(iread, *(iread.Opnd(0)))); - if (rhsOffset > 0) { - RegOperand *addrOpnd = &LoadIntoRegister(*ireadOpnd, iread.Opnd(0)->GetPrimType()); - regno_t vRegNO = NewVReg(kRegTyInt, k8ByteSize); - RegOperand *result = &CreateVirtualRegisterOperand(vRegNO); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *result, *addrOpnd, - CreateImmOperand(rhsOffset, k64BitSize, false))); - } - - CreateCallStructMemcpyToParamReg(*ty, structCopyOffset, parmLocator, srcOpnds); - structCopyOffset += static_cast(RoundUp(symSize, GetPointerSize())); - } else { - SelectParmListIreadLargeAggregate(iread, *ty, srcOpnds, parmLocator, structCopyOffset, rhsOffset); - } - } else { - CHECK_FATAL(0, "NYI"); + if (!preCopyed && mirType.GetPrimType() == PTY_agg) { + DEBUG_ASSERT(opnd.IsMemoryAccessOperand(), "NIY, must be mem opnd"); + auto &actOpnd = CreateMemOpnd(RSP, memOffset, k64BitSize); + auto mirSize = CGOptions::IsBigEndian() ? static_cast(RoundUp(mirType.GetSize(), k8ByteSize)) + : static_cast(mirType.GetSize()); + // can't use libmemcpy, it will modify parm reg + SelectInsnMemCopy(actOpnd, static_cast(opnd), mirSize); + return; } -} -size_t AArch64CGFunc::SelectParmListGetStructReturnSize(StmtNode &naryNode) -{ - if (naryNode.GetOpCode() == OP_call) { - CallNode &callNode = static_cast(naryNode); - MIRFunction *callFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx()); - TyIdx retIdx = callFunc->GetReturnTyIdx(); - if (callFunc->IsFirstArgReturn()) { - MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callFunc->GetFormalDefVec()[0].formalTyIdx); - return GetBecommon().GetTypeSize(static_cast(ty)->GetPointedTyIdx()); - } - size_t retSize = GetBecommon().GetTypeSize(retIdx.GetIdx()); - if ((retSize == 0) && callFunc->IsReturnStruct()) { - TyIdx tyIdx = callFunc->GetFuncRetStructTyIdx(); - return GetBecommon().GetTypeSize(tyIdx); - } - return retSize; - } else if (naryNode.GetOpCode() == OP_icall) { - IcallNode &icallNode = static_cast(naryNode); - CallReturnVector *p2nrets = &icallNode.GetReturnVec(); - if (p2nrets->size() == k1ByteSize) { - StIdx stIdx = (*p2nrets)[0].first; - MIRSymbol *sym = GetBecommon().GetMIRModule().CurFunction()->GetSymTab()->GetSymbolFromStIdx(stIdx.Idx()); - if (sym != nullptr) { - return GetBecommon().GetTypeSize(sym->GetTyIdx().GetIdx()); - } - } - } else if (naryNode.GetOpCode() == OP_icallproto) { - IcallNode &icallProto = static_cast(naryNode); - MIRFuncType *funcTy = - static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(icallProto.GetRetTyIdx())); - if (funcTy->FirstArgReturn()) { - MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcTy->GetNthParamType(0)); - return GetBecommon().GetTypeSize(static_cast(ty)->GetPointedTyIdx()); - } - return GetBecommon().GetTypeSize(funcTy->GetRetTyIdx()); + if (IsInt128Ty(mirType.GetPrimType())) { + DEBUG_ASSERT(!preCopyed, "NIY"); + MemOperand &mem = CreateMemOpnd(RSP, memOffset, GetPrimTypeBitSize(PTY_u128)); + mem.SetStackArgMem(true); + SelectCopy(mem, PTY_u128, opnd, PTY_u128); + return; } - return 0; -} -void AArch64CGFunc::SelectParmListPreprocessLargeStruct(BaseNode &argExpr, int32 &structCopyOffset) -{ - uint64 symSize; - int32 rhsOffset = 0; - if (argExpr.GetOpCode() == OP_dread) { - DreadNode &dread = static_cast(argExpr); - MIRSymbol *sym = GetBecommon().GetMIRModule().CurFunction()->GetLocalOrGlobalSymbol(dread.GetStIdx()); - MIRType *ty = sym->GetType(); - if (dread.GetFieldID() != 0) { - MIRStructType *structty = static_cast(ty); - ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(structty->GetFieldTyIdx(dread.GetFieldID())); - rhsOffset = GetBecommon().GetFieldOffset(*structty, dread.GetFieldID()).first; - } - symSize = GetBecommon().GetTypeSize(ty->GetTypeIndex().GetIdx()); - if (symSize > kParmMemcpySize) { - CreateCallStructParamMemcpy(*sym, static_cast(symSize), structCopyOffset, rhsOffset); - structCopyOffset += static_cast(RoundUp(symSize, GetPointerSize())); - } else if (symSize > k16ByteSize) { - uint32 numMemOp = static_cast(RoundUp(symSize, GetPointerSize()) / GetPointerSize()); - structCopyOffset += static_cast(numMemOp * GetPointerSize()); - } - } else if (argExpr.GetOpCode() == OP_iread) { - IreadNode &iread = static_cast(argExpr); - MIRPtrType *pointerty = - static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread.GetTyIdx())); - MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->GetPointedTyIdx()); - if (iread.GetFieldID() != 0) { - MIRStructType *structty = static_cast(ty); - ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(structty->GetFieldTyIdx(iread.GetFieldID())); - rhsOffset = GetBecommon().GetFieldOffset(*structty, iread.GetFieldID()).first; - } - symSize = GetBecommon().GetTypeSize(ty->GetTypeIndex().GetIdx()); - if (symSize > kParmMemcpySize) { - RegOperand *ireadOpnd = static_cast(HandleExpr(iread, *(iread.Opnd(0)))); - RegOperand *addrOpnd = &LoadIntoRegister(*ireadOpnd, iread.Opnd(0)->GetPrimType()); - if (rhsOffset > 0) { - regno_t vRegNO = NewVReg(kRegTyInt, k8ByteSize); - RegOperand *result = &CreateVirtualRegisterOperand(vRegNO); - GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(MOP_xaddrri12, *result, *addrOpnd, - CreateImmOperand(rhsOffset, k64BitSize, false))); - addrOpnd = result; - } - - CreateCallStructParamMemcpy(*addrOpnd, static_cast(symSize), structCopyOffset, rhsOffset); - structCopyOffset += static_cast(RoundUp(symSize, GetPointerSize())); - } else if (symSize > k16ByteSize) { - uint32 numMemOp = static_cast(RoundUp(symSize, GetPointerSize()) / GetPointerSize()); - structCopyOffset += static_cast(numMemOp * GetPointerSize()); - } + PrimType primType = preCopyed ? PTY_a64 : mirType.GetPrimType(); + CHECK_FATAL(primType != PTY_i128 && primType != PTY_u128, "NIY, i128 is unsupported"); + auto &valReg = LoadIntoRegister(opnd, primType); + auto &actMemOpnd = CreateMemOpnd(RSP, memOffset, GetPrimTypeBitSize(primType)); + Insn &strInsn = GetInsnBuilder()->BuildInsn(PickStInsn(GetPrimTypeBitSize(primType), primType), valReg, actMemOpnd); + actMemOpnd.SetStackArgMem(true); + if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel2 && insnForStackArgs.size() < kShiftAmount12) { + (void)insnForStackArgs.emplace_back(&strInsn); + } else { + GetCurBB()->AppendInsn(strInsn); } } @@ -8546,24 +8170,6 @@ bool AArch64CGFunc::MarkParmListCall(BaseNode &expr) return false; } -void AArch64CGFunc::SelectParmListPreprocess(const StmtNode &naryNode, size_t start, std::set &specialArgs) -{ - size_t i = start; - int32 structCopyOffset = GetMaxParamStackSize() - GetStructCopySize(); - for (; i < naryNode.NumOpnds(); ++i) { - BaseNode *argExpr = naryNode.Opnd(i); - PrimType primType = argExpr->GetPrimType(); - if (MarkParmListCall(*argExpr)) { - (void)specialArgs.emplace(i); - } - DEBUG_ASSERT(primType != PTY_void, "primType should not be void"); - if (primType != PTY_agg) { - continue; - } - SelectParmListPreprocessLargeStruct(*argExpr, structCopyOffset); - } -} - /* SelectParmList generates an instrunction for each of the parameters to load the parameter value into the corresponding register. @@ -8572,155 +8178,95 @@ void AArch64CGFunc::SelectParmListPreprocess(const StmtNode &naryNode, size_t st */ void AArch64CGFunc::SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, bool isCallNative) { - size_t i = 0; + size_t opndIdx = 0; + // the first opnd of ICallNode is not parameter of function if (naryNode.GetOpCode() == OP_icall || naryNode.GetOpCode() == OP_icallproto || isCallNative) { - i++; - } - std::set specialArgs; - SelectParmListPreprocess(naryNode, i, specialArgs); - bool specialArg = false; - bool firstArgReturn = false; - MIRFunction *callee = nullptr; - if (dynamic_cast(&naryNode) != nullptr) { - auto calleePuIdx = static_cast(naryNode).GetPUIdx(); - callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(calleePuIdx); - firstArgReturn = callee->IsFirstArgReturn(); - } else if (naryNode.GetOpCode() == OP_icallproto) { - IcallNode *icallnode = &static_cast(naryNode); - MIRFuncType *funcType = - static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(icallnode->GetRetTyIdx())); - firstArgReturn = funcType->FirstArgReturn(); + opndIdx++; } + auto [callee, calleeType] = GetCalleeFunction(naryNode); + + std::vector argsDesc; + std::vector regMapForTmpBB; + bool hasSpecialArg = SelectParmListPreprocess(naryNode, opndIdx, argsDesc, callee); BB *curBBrecord = GetCurBB(); BB *tmpBB = nullptr; - if (!specialArgs.empty()) { + if (hasSpecialArg) { tmpBB = CreateNewBB(); - specialArg = true; } + AArch64CallConvImpl parmLocator(GetBecommon()); CCLocInfo ploc; - int32 structCopyOffset = GetMaxParamStackSize() - GetStructCopySize(); std::vector insnForStackArgs; - uint32 stackArgsCount = 0; - for (uint32 pnum = 0; i < naryNode.NumOpnds(); ++i, ++pnum) { - if (specialArg) { + + for (size_t i = 0; i < argsDesc.size(); ++i) { + if (hasSpecialArg) { DEBUG_ASSERT(tmpBB, "need temp bb for lower priority args"); - SetCurBB(specialArgs.count(i) ? *curBBrecord : *tmpBB); - } - bool is64x1vec = false; - MIRType *ty = nullptr; - BaseNode *argExpr = naryNode.Opnd(i); - PrimType primType = argExpr->GetPrimType(); - DEBUG_ASSERT(primType != PTY_void, "primType should not be void"); - if (callee != nullptr && pnum < callee->GetFormalCount() && callee->GetFormal(pnum) != nullptr) { - is64x1vec = callee->GetFormal(pnum)->GetAttr(ATTR_oneelem_simd); - } - switch (argExpr->op) { - case OP_dread: { - DreadNode *dNode = static_cast(argExpr); - MIRSymbol *symbol = GetFunction().GetLocalOrGlobalSymbol(dNode->GetStIdx()); - if (dNode->GetFieldID() != 0) { - MIRStructType *structType = static_cast(symbol->GetType()); - DEBUG_ASSERT(structType != nullptr, "SelectParmList: non-zero fieldID for non-structure"); - FieldAttrs fa = structType->GetFieldAttrs(dNode->GetFieldID()); - is64x1vec = fa.GetAttr(FLDATTR_oneelem_simd); - } else { - is64x1vec = symbol->GetAttr(ATTR_oneelem_simd); - } - break; - } - case OP_iread: { - IreadNode *iNode = static_cast(argExpr); - MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iNode->GetTyIdx()); - MIRPtrType *ptrTyp = static_cast(type); - DEBUG_ASSERT(ptrTyp != nullptr, "expect a pointer type at iread node"); - MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrTyp->GetPointedTyIdx()); - if (iNode->GetFieldID() != 0) { - MIRStructType *structType = static_cast(pointedTy); - FieldAttrs fa = structType->GetFieldAttrs(iNode->GetFieldID()); - is64x1vec = fa.GetAttr(FLDATTR_oneelem_simd); - } else { - TypeAttrs ta = static_cast(ptrTyp)->GetTypeAttrs(); - is64x1vec = ta.GetAttr(ATTR_oneelem_simd); - } - break; - } - case OP_constval: { - CallNode *call = safe_cast(&naryNode); - if (call == nullptr) { - break; - } - MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(call->GetPUIdx()); - if (fn == nullptr || fn->GetFormalCount() == 0 || fn->GetFormalCount() <= pnum) { - break; - } - is64x1vec = fn->GetFormalDefAt(pnum).formalAttrs.GetAttr(ATTR_oneelem_simd); - break; - } - default: - break; - } - /* use alloca */ - if (primType == PTY_agg) { - SelectParmListForAggregate(*argExpr, srcOpnds, parmLocator, structCopyOffset); - continue; - } - ty = GlobalTables::GetTypeTable().GetTypeTable()[static_cast(primType)]; - RegOperand *expRegOpnd = nullptr; - Operand *opnd = HandleExpr(naryNode, *argExpr); - if (opnd->GetKind() == Operand::kOpdRegister && static_cast(opnd)->GetIF64Vec()) { - is64x1vec = true; - } - if (!opnd->IsRegister()) { - opnd = &LoadIntoRegister(*opnd, primType); + SetCurBB(argsDesc[i].isSpecialArg ? *curBBrecord : *tmpBB); } - expRegOpnd = static_cast(opnd); - if ((pnum == 0) && firstArgReturn) { - parmLocator.InitCCLocInfo(ploc); - ploc.reg0 = R8; - } else { - parmLocator.LocateNextParm(*ty, ploc); - } - /* is64x1vec should be an int64 value in an FP/simd reg for ABI compliance, - convert R-reg to equivalent V-reg */ - PrimType destPrimType = primType; - if (is64x1vec && ploc.reg0 != kRinvalid && ploc.reg0 < R7) { - ploc.reg0 = AArch64Abi::floatParmRegs[static_cast(ploc.reg0) - 1]; - destPrimType = PTY_f64; + auto *mirType = argsDesc[i].mirType; + + // get param opnd, for unpreCody agg, opnd must be mem opnd + Operand *opnd = nullptr; + auto preCopyed = argsDesc[i].preCopyed; + if (preCopyed) { // preCopyed agg, passed by address + naryNode.SetMayTailcall(false); // has preCopyed arguments, don't do tailcall + opnd = &CreateVirtualRegisterOperand(NewVReg(kRegTyInt, k8ByteSize)); + auto &spReg = GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); + SelectAdd(*opnd, spReg, CreateImmOperand(argsDesc[i].offset, k64BitSize, false), PTY_a64); + } else if (mirType->GetPrimType() == PTY_agg) { + opnd = SelectRhsMemOpnd(*argsDesc[i].argExpr); + } else { // base type, clac true val + opnd = &LoadIntoRegister(*HandleExpr(naryNode, *argsDesc[i].argExpr), mirType->GetPrimType()); } + parmLocator.LocateNextParm(*mirType, ploc, (i == 0), calleeType); - /* skip unused args */ - if (callee != nullptr && callee->GetFuncDesc().IsArgUnused(pnum)) + // skip unused args + if (callee && callee->GetFuncDesc().IsArgUnused(i)) { continue; + } - if (ploc.reg0 != kRinvalid) { /* load to the register. */ - CHECK_FATAL(expRegOpnd != nullptr, "null ptr check"); - RegOperand &parmRegOpnd = GetOrCreatePhysicalRegisterOperand( - static_cast(ploc.reg0), expRegOpnd->GetSize(), GetRegTyFromPrimTy(destPrimType)); - SelectCopy(parmRegOpnd, destPrimType, *expRegOpnd, primType); - srcOpnds.PushOpnd(parmRegOpnd); - } else { /* store to the memory segment for stack-passsed arguments. */ - if (CGOptions::IsBigEndian()) { - if (GetPrimTypeBitSize(primType) < k64BitSize) { - ploc.memOffset = ploc.memOffset + static_cast(k4BitSize); - } - } - MemOperand &actMemOpnd = CreateMemOpnd(RSP, ploc.memOffset, GetPrimTypeBitSize(primType)); - Insn &strInsn = GetInsnBuilder()->BuildInsn(PickStInsn(GetPrimTypeBitSize(primType), primType), *expRegOpnd, - actMemOpnd); - actMemOpnd.SetStackArgMem(true); - if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel1 && stackArgsCount < kShiftAmount12) { - (void)insnForStackArgs.emplace_back(&strInsn); - stackArgsCount++; + if (ploc.reg0 != kRinvalid) { // load to the register. + if (mirType->GetPrimType() == PTY_agg && !preCopyed) { + SelectParmListSmallStruct(*mirType, ploc, *opnd, srcOpnds, argsDesc[i].isSpecialArg, regMapForTmpBB); + } else if (IsInt128Ty(mirType->GetPrimType())) { + SelectParmListForInt128(*opnd, srcOpnds, ploc, argsDesc[i].isSpecialArg, regMapForTmpBB); } else { - GetCurBB()->AppendInsn(strInsn); + CHECK_FATAL(ploc.reg1 == kRinvalid, "NIY"); + auto &phyReg = GetOrCreatePhysicalRegisterOperand(static_cast(ploc.reg0), + GetPrimTypeBitSize(ploc.primTypeOfReg0), + GetRegTyFromPrimTy(ploc.primTypeOfReg0)); + DEBUG_ASSERT(opnd->IsRegister(), "NIY, must be reg"); + if (!DoCallerEnsureValidParm(phyReg, static_cast(*opnd), ploc.primTypeOfReg0)) { + if (argsDesc[i].isSpecialArg) { + regMapForTmpBB.emplace_back(RegMapForPhyRegCpy( + &phyReg, ploc.primTypeOfReg0, static_cast(opnd), ploc.primTypeOfReg0)); + } else { + SelectCopy(phyReg, ploc.primTypeOfReg0, *opnd, ploc.primTypeOfReg0); + } + } + srcOpnds.PushOpnd(phyReg); } + continue; } - DEBUG_ASSERT(ploc.reg1 == 0, "SelectCall NYI"); + + // store to the memory segment for stack-passsed arguments. + if (CGOptions::IsBigEndian() && ploc.memSize < static_cast(k8ByteSize)) { + ploc.memOffset = ploc.memOffset + static_cast(k4ByteSize); + } + SelectParmListPassByStack(*mirType, *opnd, static_cast(ploc.memOffset), preCopyed, insnForStackArgs); } - if (specialArg) { + // if we have stack-passed arguments, don't do tailcall + parmLocator.InitCCLocInfo(ploc); + if (ploc.memOffset != 0) { + naryNode.SetMayTailcall(false); + } + if (hasSpecialArg) { DEBUG_ASSERT(tmpBB, "need temp bb for lower priority args"); + SetCurBB(*tmpBB); + for (auto it : regMapForTmpBB) { + SelectCopy(*it.destReg, it.destType, *it.srcReg, it.srcType); + } curBBrecord->InsertAtEnd(*tmpBB); SetCurBB(*curBBrecord); } @@ -8729,6 +8275,36 @@ void AArch64CGFunc::SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, bo } } +bool AArch64CGFunc::DoCallerEnsureValidParm(RegOperand &destOpnd, RegOperand &srcOpnd, PrimType formalPType) +{ + Insn *insn = nullptr; + switch (formalPType) { + case PTY_u1: { + ImmOperand &lsbOpnd = CreateImmOperand(maplebe::k0BitSize, srcOpnd.GetSize(), false); + ImmOperand &widthOpnd = CreateImmOperand(maplebe::k1BitSize, srcOpnd.GetSize(), false); + bool is64Bit = (srcOpnd.GetSize() == maplebe::k64BitSize); + insn = &GetInsnBuilder()->BuildInsn(is64Bit ? MOP_xubfxrri6i6 : MOP_wubfxrri5i5, destOpnd, srcOpnd, lsbOpnd, + widthOpnd); + break; + } + case PTY_u8: + case PTY_i8: + insn = &GetInsnBuilder()->BuildInsn(MOP_xuxtb32, destOpnd, srcOpnd); + break; + case PTY_u16: + case PTY_i16: + insn = &GetInsnBuilder()->BuildInsn(MOP_xuxth32, destOpnd, srcOpnd); + break; + default: + break; + } + if (insn != nullptr) { + GetCurBB()->AppendInsn(*insn); + return true; + } + return false; +} + void AArch64CGFunc::SelectParmListNotC(StmtNode &naryNode, ListOperand &srcOpnds) { size_t i = 0; @@ -9319,7 +8895,7 @@ void AArch64CGFunc::SelectReturn(Operand *opnd0) MIRType *retTyp = is64x1vec ? floatType : GetFunction().GetReturnType(); CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind()); CCLocInfo retMech; - retLocator.InitReturnInfo(*retTyp, retMech); + retLocator.LocateRetVal(*retTyp, retMech); if ((retMech.GetRegCount() > 0) && (opnd0 != nullptr)) { RegType regTyp = is64x1vec ? kRegTyFloat : GetRegTyFromPrimTy(retMech.GetPrimTypeOfReg0()); PrimType oriPrimType = is64x1vec ? GetFunction().GetReturnType()->GetPrimType() : retMech.GetPrimTypeOfReg0(); @@ -10025,7 +9601,7 @@ const Operand *AArch64CGFunc::GetRflag() const return rcc; } -Operand &AArch64CGFunc::GetOrCreatevaryreg() +RegOperand &AArch64CGFunc::GetOrCreatevaryreg() { if (vary == nullptr) { regno_t vRegNO = NewVReg(kRegTyVary, k8ByteSize); @@ -10109,7 +9685,7 @@ void AArch64CGFunc::SelectLibCallNArg(const std::string &funcName, std::vectorGetMemSegmentKind(); DEBUG_ASSERT(((sgKind == kMsArgsRegPassed) || (sgKind == kMsLocals) || (sgKind == kMsRefLocals) || (sgKind == kMsArgsToStkPass) || (sgKind == kMsArgsStkPassed)), "NYI"); - if (sgKind == kMsArgsStkPassed) { + if (sgKind == kMsArgsStkPassed || sgKind == kMsCold) { return &GetOrCreatevaryreg(); } @@ -10411,7 +9987,7 @@ AArch64reg AArch64CGFunc::GetReturnRegisterNumber() { CCImpl &retLocator = *GetOrCreateLocator(GetCurCallConvKind()); CCLocInfo retMech; - retLocator.InitReturnInfo(*(GetFunction().GetReturnType()), retMech); + retLocator.LocateRetVal(*(GetFunction().GetReturnType()), retMech); if (retMech.GetRegCount() > 0) { return static_cast(retMech.GetReg0()); } @@ -12872,4 +12448,39 @@ bool AArch64CGFunc::DistanceCheck(const BB &bb, LabelIdx targLabIdx, uint32 targ } CHECK_FATAL(false, "CFG error"); } + +AArch64CGFunc::SplittedInt128 AArch64CGFunc::SplitInt128(Operand &opnd) +{ + DEBUG_ASSERT(opnd.IsRegister(), "expected register opnd"); + auto vecTy = PTY_v2u64; + auto scTy = PTY_u64; + Operand &low = *SelectVectorGetElement(scTy, &opnd, vecTy, 0); + Operand &high = *SelectVectorGetElement(scTy, &opnd, vecTy, 1); + return {low, high}; +} + +void AArch64CGFunc::SelectParmListForInt128(Operand &opnd, ListOperand &srcOpnds, const CCLocInfo &ploc, + bool isSpecialArg, std::vector ®MapForTmpBB) +{ + DEBUG_ASSERT(ploc.reg0 != kRinvalid && ploc.reg1 != kRinvalid, ""); + + auto splitOpnd = SplitInt128(opnd); + auto reg0 = static_cast(ploc.reg0); + auto reg1 = static_cast(ploc.reg1); + RegOperand &low = GetOrCreatePhysicalRegisterOperand(reg0, k64BitSize, kRegTyInt); + RegOperand &high = GetOrCreatePhysicalRegisterOperand(reg1, k64BitSize, kRegTyInt); + + auto cpyTy = PTY_u64; + if (isSpecialArg) { + regMapForTmpBB.emplace_back(RegMapForPhyRegCpy(&low, cpyTy, static_cast(&splitOpnd.low), cpyTy)); + regMapForTmpBB.emplace_back( + RegMapForPhyRegCpy(&high, cpyTy, static_cast(&splitOpnd.high), cpyTy)); + } else { + SelectCopy(low, cpyTy, splitOpnd.low, cpyTy); + SelectCopy(high, cpyTy, splitOpnd.high, cpyTy); + } + + srcOpnds.PushOpnd(low); + srcOpnds.PushOpnd(high); +} } /* namespace maplebe */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_color_ra.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_color_ra.cpp index b319df61e46fee0a3faaf2367ab5c6494a30796f..eb8705e238449149c000e61f0f4e96e454342a9e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_color_ra.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_color_ra.cpp @@ -229,7 +229,7 @@ std::vector LiveRange::Rematerialize(AArch64CGFunc *cgFunc, RegOperand & Insn *insn = &cgFunc->GetInsnBuilder()->BuildInsn(MOP_xaddrri12, regOp, *cgFunc->GetBaseReg(*symLoc), *offsetOp); - if (CGOptions::kVerboseCG) { + if (CGOptions::GetInstance().GenerateVerboseCG()) { std::string comm = "local/formal var: "; comm.append(symbol->GetName()); insn->SetComment(comm); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_memlayout.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_memlayout.cpp index f22899365d982ec45147cd9f3f6b86fedb1f04ec..6745748d5ca7b10ea7fea7da1e8a9e883d57049f 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_memlayout.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_memlayout.cpp @@ -159,7 +159,7 @@ void AArch64MemLayout::LayoutVarargParams() } } MIRType *ty = func->GetNthParamType(i); - parmlocator.LocateNextParm(*ty, ploc, i == 0, func); + parmlocator.LocateNextParm(*ty, ploc, i == 0, func->GetMIRFuncType()); if (ploc.reg0 != kRinvalid) { if (ploc.reg0 >= R0 && ploc.reg0 <= R7) { nIntRegs++; @@ -241,7 +241,7 @@ void AArch64MemLayout::LayoutFormalParams() } MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(mirFunction->GetFormalDefVec()[i].formalTyIdx); uint32 ptyIdx = ty->GetTypeIndex(); - parmLocator.LocateNextParm(*ty, ploc, i == 0, mirFunction); + parmLocator.LocateNextParm(*ty, ploc, i == 0, mirFunction->GetMIRFuncType()); if (ploc.reg0 != kRinvalid) { /* register */ symLoc->SetRegisters(static_cast(ploc.reg0), static_cast(ploc.reg1), static_cast(ploc.reg2), static_cast(ploc.reg3)); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp index 91624c8ca41a4e397de52843ccde617ff25d021e..cc28dc1ca88dc2b068d84102e91c894318e13448 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp @@ -18,6 +18,7 @@ #include "cg_option.h" #include "cgfunc.h" +#define PROEPILOG_DUMP CG_DEBUG_FUNC(cgFunc) namespace maplebe { using namespace maple; @@ -63,280 +64,86 @@ inline void AppendInstructionTo(Insn &insn, CGFunc &func) } } // namespace -bool AArch64GenProEpilog::HasLoop() -{ - FOR_ALL_BB(bb, &cgFunc) { - if (bb->IsBackEdgeDest()) { - return true; - } - FOR_BB_INSNS_REV(insn, bb) { - if (!insn->IsMachineInstruction()) { - continue; - } - if (insn->HasLoop()) { - return true; - } - } - } - return false; -} - -/* - * Remove redundant mov and mark optimizable bl/blr insn in the BB. - * Return value: true to call this modified block again. - */ -bool AArch64GenProEpilog::OptimizeTailBB(BB &bb, MapleSet &callInsns, const BB &exitBB) const -{ - if (bb.NumInsn() == 1 && - (bb.GetLastInsn()->GetMachineOpcode() != MOP_xbr && bb.GetLastInsn()->GetMachineOpcode() != MOP_xblr && - bb.GetLastInsn()->GetMachineOpcode() != MOP_xbl && bb.GetLastInsn()->GetMachineOpcode() != MOP_xuncond)) { - return false; - } - FOR_BB_INSNS_REV_SAFE(insn, &bb, prev_insn) { - if (!insn->IsMachineInstruction() || AArch64isa::IsPseudoInstruction(insn->GetMachineOpcode())) { - continue; - } - MOperator insnMop = insn->GetMachineOpcode(); - switch (insnMop) { - case MOP_xldr: - case MOP_xldp: - case MOP_dldr: - case MOP_dldp: { - if (bb.GetKind() == BB::kBBReturn) { - RegOperand ® = static_cast(insn->GetOperand(0)); - if (AArch64Abi::IsCalleeSavedReg(static_cast(reg.GetRegisterNumber()))) { - break; /* inserted restore from calleeregs-placement, ignore */ - } - } - return false; - } - case MOP_wmovrr: - case MOP_xmovrr: { - CHECK_FATAL(insn->GetOperand(0).IsRegister(), "operand0 is not register"); - CHECK_FATAL(insn->GetOperand(1).IsRegister(), "operand1 is not register"); - auto ®1 = static_cast(insn->GetOperand(0)); - auto ®2 = static_cast(insn->GetOperand(1)); - - if (reg1.GetRegisterNumber() != R0 || reg2.GetRegisterNumber() != R0) { - return false; - } - - bb.RemoveInsn(*insn); - break; - } - case MOP_xblr: { - if (insn->GetOperand(0).IsRegister()) { - RegOperand ® = static_cast(insn->GetOperand(0)); - if (AArch64Abi::IsCalleeSavedReg(static_cast(reg.GetRegisterNumber()))) { - return false; /* can't tailcall, register will be overwritten by restore */ - } - } - /* flow through */ - } - [[clang::fallthrough]]; - case MOP_xbl: { - callInsns.insert(insn); - return false; - } - case MOP_xuncond: { - LabelOperand &bLab = static_cast(insn->GetOperand(0)); - if (exitBB.GetLabIdx() == bLab.GetLabelIndex()) { - break; - } - return false; - } - default: - return false; - } - } - - return true; -} - -/* Recursively invoke this function for all predecessors of exitBB */ -void AArch64GenProEpilog::TailCallBBOpt(BB &bb, MapleSet &callInsns, BB &exitBB) +bool AArch64GenProEpilog::NeedProEpilog() { - /* callsite also in the return block as in "if () return; else foo();" - call in the exit block */ - if (!bb.IsEmpty() && !OptimizeTailBB(bb, callInsns, exitBB)) { - return; - } - - for (auto tmpBB : bb.GetPreds()) { - if (tmpBB->GetSuccs().size() != 1 || !tmpBB->GetEhSuccs().empty() || - (tmpBB->GetKind() != BB::kBBFallthru && tmpBB->GetKind() != BB::kBBGoto)) { - continue; - } - - if (OptimizeTailBB(*tmpBB, callInsns, exitBB)) { - TailCallBBOpt(*tmpBB, callInsns, exitBB); - } + if (cgFunc.GetMirModule().GetSrcLang() != kSrcLangC) { + return true; + } else if (cgFunc.GetFunction().GetAttr(FUNCATTR_varargs) || cgFunc.HasVLAOrAlloca()) { + return true; } -} -/* - * If a function without callee-saved register, and end with a function call, - * then transfer bl/blr to b/br. - * Return value: true if function do not need Prologue/Epilogue. false otherwise. - */ -bool AArch64GenProEpilog::TailCallOpt() -{ - /* Count how many call insns in the whole function. */ - uint32 nCount = 0; - bool hasGetStackClass = false; - - FOR_ALL_BB(bb, &cgFunc) { - FOR_BB_INSNS(insn, bb) { - if (insn->IsMachineInstruction() && insn->IsCall()) { - ++nCount; + FOR_ALL_BB(bb, &cgFunc) + { + FOR_BB_INSNS_REV(insn, bb) + { + if (insn->IsMachineInstruction() && (insn->IsCall() || insn->IsSpecialCall())) { + return true; } } } - if ((nCount > 0 && cgFunc.GetFunction().GetAttr(FUNCATTR_interface)) || hasGetStackClass) { - return false; - } - - if (nCount == 0) { - // no bl instr in any bb + auto &aarchCGFunc = static_cast(cgFunc); + const MapleVector ®sToRestore = (aarchCGFunc.GetProEpilogSavedRegs().empty()) + ? aarchCGFunc.GetCalleeSavedRegs() + : aarchCGFunc.GetProEpilogSavedRegs(); + size_t calleeSavedRegSize = kOneRegister; + CHECK_FATAL(regsToRestore.size() >= calleeSavedRegSize, "Forgot LR ?"); + if (regsToRestore.size() > calleeSavedRegSize || aarchCGFunc.HasStackLoadStore() || + static_cast(cgFunc.GetMemlayout())->GetSizeOfLocals() > 0 || + static_cast(cgFunc.GetMemlayout())->GetSizeOfCold() > 0 || + cgFunc.GetFunction().GetAttr(FUNCATTR_callersensitive)) { return true; } - - size_t exitBBSize = cgFunc.GetExitBBsVec().size(); - /* For now to reduce complexity */ - - BB *exitBB = nullptr; - if (exitBBSize == 0) { - if (cgFunc.GetLastBB()->GetPrev()->GetFirstStmt() == cgFunc.GetCleanupLabel() && - cgFunc.GetLastBB()->GetPrev()->GetPrev() != nullptr) { - exitBB = cgFunc.GetLastBB()->GetPrev()->GetPrev(); - } else { - exitBB = cgFunc.GetLastBB()->GetPrev(); - } - } else { - exitBB = cgFunc.GetExitBBsVec().front(); - } - uint32 i = 1; - size_t optCount = 0; - do { - MapleSet callInsns(tmpAlloc.Adapter()); - TailCallBBOpt(*exitBB, callInsns, *exitBB); - if (callInsns.size() != 0) { - optCount += callInsns.size(); - (void)exitBB2CallSitesMap.emplace(exitBB, callInsns); - } - if (i < exitBBSize) { - exitBB = cgFunc.GetExitBBsVec()[i]; - ++i; - } else { - break; - } - } while (1); - - /* regular calls exist in function */ - if (nCount != optCount) { - return false; + if (cgFunc.GetCG()->IsStackProtectorAll()) { + return true; } - return true; + return false; } -static bool IsAddOrSubOp(MOperator mOp) +// find a idle register, default R30 +AArch64reg AArch64GenProEpilog::GetStackGuardRegister(const BB &bb) const { - switch (mOp) { - case MOP_xaddrrr: - case MOP_xaddrrrs: - case MOP_xxwaddrrre: - case MOP_xaddrri24: - case MOP_xaddrri12: - case MOP_xsubrrr: - case MOP_xsubrrrs: - case MOP_xxwsubrrre: - case MOP_xsubrri12: - return true; - default: - return false; + if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) { + return R30; } -} - -/* tailcallopt cannot be used if stack address of this function is taken and passed, - not checking the passing for now, just taken */ -static bool IsStackAddrTaken(CGFunc &cgFunc) -{ - FOR_ALL_BB(bb, &cgFunc) { - FOR_BB_INSNS_REV(insn, bb) { - if (IsAddOrSubOp(insn->GetMachineOpcode())) { - for (uint32 i = 0; i < insn->GetOperandSize(); i++) { - if (insn->GetOperand(i).IsRegister()) { - RegOperand ® = static_cast(insn->GetOperand(i)); - if (reg.GetRegisterNumber() == R29 || reg.GetRegisterNumber() == R31 || - reg.GetRegisterNumber() == RSP) { - return true; - } - } - } + for (regno_t reg = R9; reg < R29; ++reg) { + if (bb.GetLiveInRegNO().count(reg) == 0 && reg != R16) { + if (!AArch64Abi::IsCalleeSavedReg(static_cast(reg))) { + return static_cast(reg); } } } - return false; + return R30; } -bool AArch64GenProEpilog::NeedProEpilog() +// find two idle register, default R30 and R16 +std::pair AArch64GenProEpilog::GetStackGuardCheckRegister(const BB &bb) const { - if (cgFunc.GetMirModule().GetSrcLang() != kSrcLangC) { - return true; - } else if (cgFunc.GetFunction().GetAttr(FUNCATTR_varargs) || cgFunc.HasVLAOrAlloca()) { - return true; - } - bool funcHasCalls = false; - if (cgFunc.GetCG()->DoTailCall() && !IsStackAddrTaken(cgFunc) && !stackProtect) { - funcHasCalls = !TailCallOpt(); // return value == "no call instr/only or 1 tailcall" - } else { - FOR_ALL_BB(bb, &cgFunc) { - FOR_BB_INSNS_REV(insn, bb) { - if (insn->IsMachineInstruction() && insn->IsCall()) { - funcHasCalls = true; - } + AArch64reg stGuardReg = R30; + AArch64reg stCheckReg = R16; + if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) { + return {stGuardReg, stCheckReg}; + } + for (regno_t reg = R9; reg < R29; ++reg) { + if (bb.GetLiveOutRegNO().count(reg) == 0 && reg != R16) { + if (AArch64Abi::IsCalleeSavedReg(static_cast(reg))) { + continue; + } + if (stGuardReg == R30) { + stGuardReg = static_cast(reg); + } else { + stCheckReg = static_cast(reg); + break; } } } - auto &aarchCGFunc = static_cast(cgFunc); - const MapleVector ®sToRestore = - (!CGOptions::DoRegSavesOpt()) ? aarchCGFunc.GetCalleeSavedRegs() : aarchCGFunc.GetProEpilogSavedRegs(); - size_t calleeSavedRegSize = kTwoRegister; - CHECK_FATAL(regsToRestore.size() >= calleeSavedRegSize, "Forgot FP and LR ?"); - if (funcHasCalls || regsToRestore.size() > calleeSavedRegSize || aarchCGFunc.HasStackLoadStore() || - static_cast(cgFunc.GetMemlayout())->GetSizeOfLocals() > 0 || - cgFunc.GetFunction().GetAttr(FUNCATTR_callersensitive)) { - return true; - } - return false; + return {stGuardReg, stCheckReg}; } -void AArch64GenProEpilog::GenStackGuard(BB &bb) +// RealStackFrameSize - [GR,16] - [VR,16] - 8 (from fp to stack protect area) +// We allocate 16 byte for stack protect area +MemOperand *AArch64GenProEpilog::GetDownStack() { - if (!stackProtect) { - return; - } auto &aarchCGFunc = static_cast(cgFunc); - BB *formerCurBB = cgFunc.GetCurBB(); - aarchCGFunc.GetDummyBB()->ClearInsns(); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(true); - cgFunc.SetCurBB(*aarchCGFunc.GetDummyBB()); - - MIRSymbol *stkGuardSym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( - GlobalTables::GetStrTable().GetStrIdxFromName(std::string("__stack_chk_guard"))); - StImmOperand &stOpnd = aarchCGFunc.CreateStImmOperand(*stkGuardSym, 0, 0); - RegOperand &stAddrOpnd = - aarchCGFunc.GetOrCreatePhysicalRegisterOperand(R9, GetPointerSize() * kBitsPerByte, kRegTyInt); - aarchCGFunc.SelectAddrof(stAddrOpnd, stOpnd); - - MemOperand *guardMemOp = - aarchCGFunc.CreateMemOperand(MemOperand::kAddrModeBOi, GetPointerSize() * kBitsPerByte, stAddrOpnd, nullptr, - &aarchCGFunc.GetOrCreateOfstOpnd(0, k32BitSize), stkGuardSym); - MOperator mOp = aarchCGFunc.PickLdInsn(k64BitSize, PTY_u64); - Insn &insn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, stAddrOpnd, *guardMemOp); - insn.SetDoNotRemove(true); - cgFunc.GetCurBB()->AppendInsn(insn); - uint64 vArea = 0; if (cgFunc.GetMirModule().IsCModule() && cgFunc.GetFunction().GetAttr(FUNCATTR_varargs)) { AArch64MemLayout *ml = static_cast(cgFunc.GetMemlayout()); @@ -350,499 +157,129 @@ void AArch64GenProEpilog::GenStackGuard(BB &bb) int32 stkSize = static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); if (useFP) { - stkSize -= - (static_cast(static_cast(cgFunc.GetMemlayout())->SizeOfArgsToStackPass()) + - cgFunc.GetFunction().GetFrameReseverdSlot()); + stkSize -= static_cast(static_cast(cgFunc.GetMemlayout())->SizeOfArgsToStackPass() + + cgFunc.GetFunction().GetFrameReseverdSlot()); } int32 memSize = (stkSize - kOffset8MemPos) - static_cast(vArea); - MemOperand *downStk = aarchCGFunc.CreateStackMemOpnd(stackBaseReg, memSize, GetPointerSize() * kBitsPerByte); + MemOperand *downStk = aarchCGFunc.CreateStackMemOpnd(stackBaseReg, memSize, GetPointerBitSize()); if (downStk->GetMemVaryType() == kNotVary && aarchCGFunc.IsImmediateOffsetOutOfRange(*downStk, k64BitSize)) { - downStk = &aarchCGFunc.SplitOffsetWithAddInstruction(*downStk, k64BitSize, R10); + downStk = &aarchCGFunc.SplitOffsetWithAddInstruction(*downStk, k64BitSize, R16); } - mOp = aarchCGFunc.PickStInsn(GetPointerSize() * kBitsPerByte, PTY_u64); - Insn &tmpInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, stAddrOpnd, *downStk); - tmpInsn.SetDoNotRemove(true); - cgFunc.GetCurBB()->AppendInsn(tmpInsn); - - bb.InsertAtBeginning(*aarchCGFunc.GetDummyBB()); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(false); - cgFunc.SetCurBB(*formerCurBB); + return downStk; } -BB &AArch64GenProEpilog::GenStackGuardCheckInsn(BB &bb) +RegOperand &AArch64GenProEpilog::GenStackGuard(AArch64reg regNO) { - if (!stackProtect) { - return bb; - } - - BB *formerCurBB = cgFunc.GetCurBB(); - cgFunc.GetDummyBB()->ClearInsns(); - cgFunc.SetCurBB(*(cgFunc.GetDummyBB())); auto &aarchCGFunc = static_cast(cgFunc); + aarchCGFunc.GetDummyBB()->ClearInsns(); - const MIRSymbol *stkGuardSym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( + cgFunc.SetCurBB(*aarchCGFunc.GetDummyBB()); + + MIRSymbol *stkGuardSym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( GlobalTables::GetStrTable().GetStrIdxFromName(std::string("__stack_chk_guard"))); StImmOperand &stOpnd = aarchCGFunc.CreateStImmOperand(*stkGuardSym, 0, 0); - RegOperand &stAddrOpnd = - aarchCGFunc.GetOrCreatePhysicalRegisterOperand(R9, GetPointerSize() * kBitsPerByte, kRegTyInt); + RegOperand &stAddrOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(regNO, GetPointerBitSize(), kRegTyInt); aarchCGFunc.SelectAddrof(stAddrOpnd, stOpnd); - MemOperand *guardMemOp = - aarchCGFunc.CreateMemOperand(MemOperand::kAddrModeBOi, GetPointerSize() * kBitsPerByte, stAddrOpnd, nullptr, - &aarchCGFunc.GetOrCreateOfstOpnd(0, k32BitSize), stkGuardSym); + MemOperand *guardMemOp = aarchCGFunc.CreateMemOperand(GetPointerBitSize(), stAddrOpnd, + aarchCGFunc.CreateImmOperand(0, k32BitSize, false), false); MOperator mOp = aarchCGFunc.PickLdInsn(k64BitSize, PTY_u64); Insn &insn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, stAddrOpnd, *guardMemOp); insn.SetDoNotRemove(true); cgFunc.GetCurBB()->AppendInsn(insn); + return stAddrOpnd; +} - uint64 vArea = 0; - if (cgFunc.GetMirModule().IsCModule() && cgFunc.GetFunction().GetAttr(FUNCATTR_varargs)) { - AArch64MemLayout *ml = static_cast(cgFunc.GetMemlayout()); - if (ml->GetSizeOfGRSaveArea() > 0) { - vArea += RoundUp(ml->GetSizeOfGRSaveArea(), kAarch64StackPtrAlignment); - } - if (ml->GetSizeOfVRSaveArea() > 0) { - vArea += RoundUp(ml->GetSizeOfVRSaveArea(), kAarch64StackPtrAlignment); - } - } - - RegOperand &checkOp = - aarchCGFunc.GetOrCreatePhysicalRegisterOperand(R10, GetPointerSize() * kBitsPerByte, kRegTyInt); - int32 stkSize = static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); - if (useFP) { - stkSize -= - (static_cast(static_cast(cgFunc.GetMemlayout())->SizeOfArgsToStackPass()) + - cgFunc.GetFunction().GetFrameReseverdSlot()); - } - int32 memSize = (stkSize - kOffset8MemPos) - static_cast(vArea); - MemOperand *downStk = aarchCGFunc.CreateStackMemOpnd(stackBaseReg, memSize, GetPointerSize() * kBitsPerByte); - if (downStk->GetMemVaryType() == kNotVary && aarchCGFunc.IsImmediateOffsetOutOfRange(*downStk, k64BitSize)) { - downStk = &aarchCGFunc.SplitOffsetWithAddInstruction(*downStk, k64BitSize, R10); +void AArch64GenProEpilog::AddStackGuard(BB &bb) +{ + if (!cgFunc.GetNeedStackProtect()) { + return; } - mOp = aarchCGFunc.PickLdInsn(GetPointerSize() * kBitsPerByte, PTY_u64); - Insn &newInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, checkOp, *downStk); - newInsn.SetDoNotRemove(true); - cgFunc.GetCurBB()->AppendInsn(newInsn); + BB *formerCurBB = cgFunc.GetCurBB(); + auto &aarchCGFunc = static_cast(cgFunc); + auto &stAddrOpnd = GenStackGuard(GetStackGuardRegister(bb)); + auto mOp = aarchCGFunc.PickStInsn(GetPointerBitSize(), PTY_u64); + Insn &tmpInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, stAddrOpnd, *GetDownStack()); + tmpInsn.SetDoNotRemove(true); + cgFunc.GetCurBB()->AppendInsn(tmpInsn); - cgFunc.SelectBxor(stAddrOpnd, stAddrOpnd, checkOp, PTY_u64); - LabelIdx failLable = aarchCGFunc.CreateLabel(); - aarchCGFunc.SelectCondGoto(aarchCGFunc.GetOrCreateLabelOperand(failLable), OP_brtrue, OP_eq, stAddrOpnd, - aarchCGFunc.CreateImmOperand(0, k64BitSize, false), PTY_u64, false); + bb.InsertAtBeginning(*aarchCGFunc.GetDummyBB()); + cgFunc.SetCurBB(*formerCurBB); +} - bb.AppendBBInsns(*(cgFunc.GetCurBB())); +BB &AArch64GenProEpilog::GetOrGenStackGuardCheckFailBB(BB &bb) +{ + if (stackChkFailBB != nullptr) { + return *stackChkFailBB; + } + BB *formerCurBB = cgFunc.GetCurBB(); + auto &aarchCGFunc = static_cast(cgFunc); - LabelIdx nextBBLableIdx = aarchCGFunc.CreateLabel(); - BB *nextBB = aarchCGFunc.CreateNewBB(nextBBLableIdx, bb.IsUnreachable(), BB::kBBFallthru, bb.GetFrequency()); - bb.AppendBB(*nextBB); - bb.PushBackSuccs(*nextBB); - nextBB->PushBackPreds(bb); - cgFunc.SetCurBB(*nextBB); + // create new check fail BB + auto failLable = aarchCGFunc.CreateLabel(); + stackChkFailBB = aarchCGFunc.CreateNewBB(failLable, bb.IsUnreachable(), BB::kBBNoReturn, bb.GetFrequency()); + cgFunc.SetCurBB(*stackChkFailBB); MIRSymbol *failFunc = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( GlobalTables::GetStrTable().GetStrIdxFromName(std::string("__stack_chk_fail"))); ListOperand *srcOpnds = aarchCGFunc.CreateListOpnd(*cgFunc.GetFuncScopeAllocator()); Insn &callInsn = aarchCGFunc.AppendCall(*failFunc, *srcOpnds); callInsn.SetDoNotRemove(true); + ASSERT_NOT_NULL(cgFunc.GetLastBB()); + cgFunc.GetLastBB()->PrependBB(*stackChkFailBB); - BB *newBB = cgFunc.CreateNewBB(failLable, bb.IsUnreachable(), bb.GetKind(), bb.GetFrequency()); - nextBB->AppendBB(*newBB); - if (cgFunc.GetLastBB() == &bb) { - cgFunc.SetLastBB(*newBB); - } - bb.PushBackSuccs(*newBB); - nextBB->PushBackSuccs(*newBB); - newBB->PushBackPreds(*nextBB); - newBB->PushBackPreds(bb); - - bb.SetKind(BB::kBBIf); cgFunc.SetCurBB(*formerCurBB); - return *newBB; + return *stackChkFailBB; } -bool AArch64GenProEpilog::InsertOpndRegs(Operand &op, std::set &vecRegs) const +void AArch64GenProEpilog::GenStackGuardCheckInsn(BB &bb) { - Operand *opnd = &op; - CHECK_FATAL(opnd != nullptr, "opnd is nullptr in InsertRegs"); - if (opnd->IsList()) { - MapleList pregList = static_cast(opnd)->GetOperands(); - for (auto *preg : pregList) { - if (preg != nullptr) { - vecRegs.insert(preg->GetRegisterNumber()); - } - } - } - if (opnd->IsMemoryAccessOperand()) { /* the registers of kOpdMem are complex to be detected */ - RegOperand *baseOpnd = static_cast(opnd)->GetBaseRegister(); - if (baseOpnd != nullptr) { - vecRegs.insert(baseOpnd->GetRegisterNumber()); - } - RegOperand *indexOpnd = static_cast(opnd)->GetIndexRegister(); - if (indexOpnd != nullptr) { - vecRegs.insert(indexOpnd->GetRegisterNumber()); - } - } - if (opnd->IsRegister()) { - RegOperand *preg = static_cast(opnd); - if (preg != nullptr) { - vecRegs.insert(preg->GetRegisterNumber()); - } + if (!cgFunc.GetNeedStackProtect()) { + return; } - return true; -} -bool AArch64GenProEpilog::InsertInsnRegs(Insn &insn, bool insertSource, std::set &vecSourceRegs, - bool insertTarget, std::set &vecTargetRegs) -{ - Insn *curInsn = &insn; - for (uint32 o = 0; o < curInsn->GetOperandSize(); ++o) { - Operand &opnd = curInsn->GetOperand(o); - if (insertSource && curInsn->OpndIsUse(o)) { - InsertOpndRegs(opnd, vecSourceRegs); - } - if (insertTarget && curInsn->OpndIsDef(o)) { - InsertOpndRegs(opnd, vecTargetRegs); - } - } - return true; -} + BB *formerCurBB = cgFunc.GetCurBB(); + auto &aarchCGFunc = static_cast(cgFunc); + auto [stGuardReg, stCheckReg] = GetStackGuardCheckRegister(bb); + auto &stAddrOpnd = GenStackGuard(stGuardReg); + RegOperand &checkOp = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(stCheckReg, GetPointerBitSize(), kRegTyInt); + auto mOp = aarchCGFunc.PickLdInsn(GetPointerBitSize(), PTY_u64); + Insn &newInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, checkOp, *GetDownStack()); + newInsn.SetDoNotRemove(true); + cgFunc.GetCurBB()->AppendInsn(newInsn); -bool AArch64GenProEpilog::FindRegs(Operand &op, std::set &vecRegs) const -{ - Operand *opnd = &op; - if (opnd == nullptr || vecRegs.empty()) { - return false; - } - if (opnd->IsList()) { - MapleList pregList = static_cast(opnd)->GetOperands(); - for (auto *preg : pregList) { - if (preg->GetRegisterNumber() == R29 || vecRegs.find(preg->GetRegisterNumber()) != vecRegs.end()) { - return true; /* the opReg will overwrite or reread the vecRegs */ - } - } - } - if (opnd->IsMemoryAccessOperand()) { /* the registers of kOpdMem are complex to be detected */ - RegOperand *baseOpnd = static_cast(opnd)->GetBaseRegister(); - RegOperand *indexOpnd = static_cast(opnd)->GetIndexRegister(); - if ((baseOpnd != nullptr && baseOpnd->GetRegisterNumber() == R29) || - (indexOpnd != nullptr && indexOpnd->GetRegisterNumber() == R29)) { - return true; /* Avoid modifying data on the stack */ - } - if ((baseOpnd != nullptr && vecRegs.find(baseOpnd->GetRegisterNumber()) != vecRegs.end()) || - (indexOpnd != nullptr && vecRegs.find(indexOpnd->GetRegisterNumber()) != vecRegs.end())) { - return true; - } - } - if (opnd->IsRegister()) { - RegOperand *regOpnd = static_cast(opnd); - if (regOpnd->GetRegisterNumber() == R29 || vecRegs.find(regOpnd->GetRegisterNumber()) != vecRegs.end()) { - return true; /* dst is a target register, result_dst is a target register */ - } - } - return false; -} + cgFunc.SelectBxor(stAddrOpnd, stAddrOpnd, checkOp, PTY_u64); + auto &failBB = GetOrGenStackGuardCheckFailBB(bb); + aarchCGFunc.SelectCondGoto(aarchCGFunc.GetOrCreateLabelOperand(failBB.GetLabIdx()), OP_brtrue, OP_ne, stAddrOpnd, + aarchCGFunc.CreateImmOperand(0, k64BitSize, false), PTY_u64, false); -bool AArch64GenProEpilog::BackwardFindDependency(BB &ifbb, std::set &vecReturnSourceRegs, - std::list &existingInsns, std::list &moveInsns) -{ - /* - * Pattern match,(*) instruction are moved down below branch. - * ******************** - * curInsn: - * in predBB - * in ifBB - * in returnBB - * ********************* - * list: the insns can be moved into the coldBB - * (1) the instruction is neither a branch nor a call, except for the ifbb.GetLastInsn() - * As long as a branch insn exists, - * the fast path finding fails and the return value is false, - * but the code sinking can be continued. - * (2) the predBB is not a ifBB, - * As long as a ifBB in preds exists, - * the code sinking fails, - * but fast path finding can be continued. - * (3) the targetRegs of insns in existingInsns can neither be reread or overwrite - * (4) the sourceRegs of insns in existingInsns can not be overwrite - * (5) the sourceRegs of insns in returnBB can neither be reread or overwrite - * (6) the targetRegs and sourceRegs cannot be R29 R30, to protect the stack - * (7) modified the reg when: - * -------------- - * curInsn: move R2,R1 - * : s s s - * s s s - * -> s s s - * ------------ - * (a) all targets cannot be R1, all sources cannot be R1 - * all targets cannot be R2, all return sources cannot be R2 - * (b) the targetRegs and sourceRegs cannot be list or MemoryAccess - * (c) no ifBB in preds, no branch insns - * (d) the bits of source-R2 must be equal to the R2 - * (e) replace the R2 with R1 - */ - BB *pred = &ifbb; - std::set vecTargetRegs; /* the targrtRegs of existingInsns */ - std::set vecSourceRegs; /* the soureRegs of existingInsns */ - bool ifPred = false; /* Indicates whether a ifBB in pred exists */ - bool bl = false; /* Indicates whether a branch insn exists */ - do { - FOR_BB_INSNS_REV(insn, pred) { - /* code sinking */ - if (insn->IsImmaterialInsn()) { - moveInsns.push_back(insn); - continue; - } - /* code sinking */ - if (!insn->IsMachineInstruction()) { - moveInsns.push_back(insn); - continue; - } - /* code sinking fails, the insns must be retained in the ifBB */ - if (ifPred || insn == ifbb.GetLastInsn() || insn->IsBranch() || insn->IsCall() || insn->IsStore() || - insn->IsStorePair()) { - /* fast path finding fails */ - if (insn != ifbb.GetLastInsn() && - (insn->IsBranch() || insn->IsCall() || insn->IsStore() || insn->IsStorePair())) { - bl = true; - } - InsertInsnRegs(*insn, true, vecSourceRegs, true, vecTargetRegs); - existingInsns.push_back(insn); - continue; - } - bool allow = true; /* whether allow this insn move into the codeBB */ - for (uint32 o = 0; allow && o < insn->GetOperandSize(); ++o) { - Operand &opnd = insn->GetOperand(o); - if (insn->OpndIsDef(o)) { - allow = allow & !FindRegs(opnd, vecTargetRegs); - allow = allow & !FindRegs(opnd, vecSourceRegs); - allow = allow & !FindRegs(opnd, vecReturnSourceRegs); - } - if (insn->OpndIsUse(o)) { - allow = allow & !FindRegs(opnd, vecTargetRegs); - } - } - /* if a result_dst not allowed, this insn can be allowed on the condition of mov Rx,R0/R1, - * and tje existing insns cannot be blr - * RLR 31, RFP 32, RSP 33, RZR 34 */ - if (!ifPred && !bl && !allow && - (insn->GetMachineOpcode() == MOP_xmovrr || insn->GetMachineOpcode() == MOP_wmovrr)) { - Operand *resultOpnd = &(insn->GetOperand(0)); - Operand *srcOpnd = &(insn->GetOperand(1)); - regno_t resultNO = static_cast(resultOpnd)->GetRegisterNumber(); - regno_t srcNO = static_cast(srcOpnd)->GetRegisterNumber(); - if (!FindRegs(*resultOpnd, vecTargetRegs) && !FindRegs(*srcOpnd, vecTargetRegs) && - !FindRegs(*srcOpnd, vecSourceRegs) && !FindRegs(*srcOpnd, vecReturnSourceRegs) && - (srcNO < RLR || srcNO > RZR)) { - allow = true; /* allow on the conditional mov Rx,Rxx */ - for (auto *exit : existingInsns) { - /* the registers of kOpdMem are complex to be detected */ - for (uint32 o = 0; o < exit->GetOperandSize(); ++o) { - if (!exit->OpndIsUse(o)) { - continue; - } - Operand *opd = &(exit->GetOperand(o)); - if (opd->IsList() || opd->IsMemoryAccessOperand()) { - allow = false; - break; - } - /* Distinguish between 32-bit regs and 64-bit regs */ - if (opd->IsRegister() && static_cast(opd)->GetRegisterNumber() == resultNO && - opd != resultOpnd) { - allow = false; - break; - } - } - } - } - /* replace the R2 with R1 */ - if (allow) { - for (auto *exit : existingInsns) { - for (uint32 o = 0; o < exit->GetOperandSize(); ++o) { - if (!exit->OpndIsUse(o)) { - continue; - } - Operand *opd = &(exit->GetOperand(o)); - if (opd->IsRegister() && (opd == resultOpnd)) { - exit->SetOperand(o, *srcOpnd); - } - } - } - } - } - if (!allow) { /* all result_dsts are not target register */ - /* code sinking fails */ - InsertInsnRegs(*insn, true, vecSourceRegs, true, vecTargetRegs); - existingInsns.push_back(insn); - } else { - moveInsns.push_back(insn); - } - } - if (pred->GetPreds().empty()) { - break; - } - if (!ifPred) { - for (auto *tmPred : pred->GetPreds()) { - pred = tmPred; - /* try to find the BB without branch */ - if (tmPred->GetKind() == BB::kBBGoto || tmPred->GetKind() == BB::kBBFallthru) { - ifPred = false; - break; - } else { - ifPred = true; - } - } - } - } while (pred != nullptr); - for (std::set::iterator it = vecTargetRegs.begin(); it != vecTargetRegs.end(); ++it) { - if (AArch64Abi::IsCalleeSavedReg(static_cast(*it))) { /* flag register */ - return false; - } - } - return !bl; -} + auto chkBB = cgFunc.CreateNewBB(bb.GetLabIdx(), bb.IsUnreachable(), BB::kBBIf, bb.GetFrequency()); + chkBB->AppendBBInsns(bb); + bb.ClearInsns(); + auto *lastInsn = chkBB->GetLastMachineInsn(); + if (lastInsn != nullptr && (lastInsn->IsTailCall() || lastInsn->IsBranch())) { + chkBB->RemoveInsn(*lastInsn); + bb.AppendInsn(*lastInsn); + } + if (&bb == cgFunc.GetFirstBB()) { + cgFunc.SetFirstBB(*chkBB); + } + chkBB->AppendBBInsns(*(cgFunc.GetCurBB())); + bb.PrependBB(*chkBB); + chkBB->PushBackSuccs(bb); + auto &originPreds = bb.GetPreds(); + for (auto pred : originPreds) { + pred->ReplaceSucc(bb, *chkBB); + chkBB->PushBackPreds(*pred); + } + LabelIdx nextLable = aarchCGFunc.CreateLabel(); + bb.SetLabIdx(nextLable); + cgFunc.SetLab2BBMap(nextLable, bb); + bb.ClearPreds(); + bb.PushBackPreds(*chkBB); + chkBB->PushBackSuccs(failBB); + failBB.PushBackPreds(*chkBB); -BB *AArch64GenProEpilog::IsolateFastPath(BB &bb) -{ - /* - * Detect "if (cond) return" fast path, and move extra instructions - * to the slow path. - * Must match the following block structure. BB1 can be a series of - * single-pred/single-succ blocks. - * BB1 ops1 cmp-br to BB3 BB1 cmp-br to BB3 - * BB2 ops2 br to retBB ==> BB2 ret - * BB3 slow path BB3 ops1 ops2 - * if the detect is successful, BB3 will be used to generate prolog stuff. - */ - if (bb.GetPrev() != nullptr) { - return nullptr; - } - BB *ifBB = nullptr; - BB *returnBB = nullptr; - BB *coldBB = nullptr; - { - BB *curBB = &bb; - /* Look for straight line code */ - while (1) { - if (!curBB->GetEhSuccs().empty()) { - return nullptr; - } - if (curBB->GetSuccs().size() == 1) { - if (curBB->HasCall()) { - return nullptr; - } - BB *succ = curBB->GetSuccs().front(); - if (succ->GetPreds().size() != 1 || !succ->GetEhPreds().empty()) { - return nullptr; - } - curBB = succ; - } else if (curBB->GetKind() == BB::kBBIf) { - ifBB = curBB; - break; - } else { - return nullptr; - } - } - } - /* targets of if bb can only be reached by if bb */ - { - CHECK_FATAL(!ifBB->GetSuccs().empty(), "null succs check!"); - BB *first = ifBB->GetSuccs().front(); - BB *second = ifBB->GetSuccs().back(); - if (first->GetPreds().size() != 1 || !first->GetEhPreds().empty()) { - return nullptr; - } - if (second->GetPreds().size() != 1 || !second->GetEhPreds().empty()) { - return nullptr; - } - /* One target of the if bb jumps to a return bb */ - if (first->GetKind() != BB::kBBGoto && first->GetKind() != BB::kBBFallthru) { - return nullptr; - } - if (first->GetSuccs().size() != 1) { - return nullptr; - } - if (first->GetSuccs().front()->GetKind() != BB::kBBReturn) { - return nullptr; - } - if (first->GetSuccs().front()->GetPreds().size() != 1) { - return nullptr; - } - if (first->GetSuccs().front()->NumInsn() > kInsnNum2) { /* avoid a insn is used to debug */ - return nullptr; - } - if (second->GetSuccs().empty()) { - return nullptr; - } - returnBB = first; - coldBB = second; - } - /* Search backward looking for dependencies for the cond branch */ - std::list existingInsns; /* the insns must be retained in the ifBB (and the return BB) */ - std::list moveInsns; /* instructions to be moved to coldbb */ - /* - * The control flow matches at this point. - * Make sure the SourceRegs of the insns in returnBB (vecReturnSourceReg) cannot be overwrite. - * the regs in insns have three forms: list, MemoryAccess, or Register. - */ - CHECK_FATAL(returnBB != nullptr, "null ptr check"); - std::set vecReturnSourceRegs; - FOR_BB_INSNS_REV(insn, returnBB) { - if (!insn->IsMachineInstruction()) { - continue; - } - if (insn->IsBranch() || insn->IsCall() || insn->IsStore() || insn->IsStorePair()) { - return nullptr; - } - InsertInsnRegs(*insn, true, vecReturnSourceRegs, false, vecReturnSourceRegs); - existingInsns.push_back(insn); - } - FOR_BB_INSNS_REV(insn, returnBB->GetSuccs().front()) { - if (!insn->IsMachineInstruction()) { - continue; - } - if (insn->IsBranch() || insn->IsCall() || insn->IsStore() || insn->IsStorePair()) { - return nullptr; - } - InsertInsnRegs(*insn, true, vecReturnSourceRegs, false, vecReturnSourceRegs); - existingInsns.push_back(insn); - } - /* - * The mv is the 1st move using the parameter register leading to the branch - * The ld is the load using the parameter register indirectly for the branch - * The depMv is the move which preserves the result of the load but might - * destroy a parameter register which will be moved below the branch. - */ - bool fast = BackwardFindDependency(*ifBB, vecReturnSourceRegs, existingInsns, moveInsns); - /* move extra instructions to the slow path */ - if (!fast) { - return nullptr; - } - for (auto in : moveInsns) { - in->GetBB()->RemoveInsn(*in); - CHECK_FATAL(coldBB != nullptr, "null ptr check"); - static_cast(coldBB->InsertInsnBegin(*in)); - } - /* All instructions are in the right place, replace branch to ret bb to just ret. */ - /* Remove the lastInsn of gotoBB */ - if (returnBB->GetKind() == BB::kBBGoto) { - returnBB->RemoveInsn(*returnBB->GetLastInsn()); - } - BB *tgtBB = returnBB->GetSuccs().front(); - CHECK_FATAL(tgtBB != nullptr, "null ptr check"); - FOR_BB_INSNS(insn, tgtBB) { - returnBB->AppendInsn(*insn); /* add the insns such as MOP_xret */ - } - returnBB->AppendInsn(cgFunc.GetInsnBuilder()->BuildInsn(MOP_xret)); - /* bb is now a retbb and has no succ. */ - returnBB->SetKind(BB::kBBReturn); - auto predIt = std::find(tgtBB->GetPredsBegin(), tgtBB->GetPredsEnd(), returnBB); - tgtBB->ErasePreds(predIt); - tgtBB->ClearInsns(); - returnBB->ClearSuccs(); - if (tgtBB->GetPrev() != nullptr && tgtBB->GetNext() != nullptr) { - tgtBB->GetPrev()->SetNext(tgtBB->GetNext()); - tgtBB->GetNext()->SetPrev(tgtBB->GetPrev()); - } - SetFastPathReturnBB(tgtBB); - return coldBB; + cgFunc.SetCurBB(*formerCurBB); } MemOperand *AArch64GenProEpilog::SplitStpLdpOffsetForCalleeSavedWithAddInstruction(CGFunc &cgFunc, const MemOperand &mo, @@ -859,14 +296,11 @@ MemOperand *AArch64GenProEpilog::SplitStpLdpOffsetForCalleeSavedWithAddInstructi * in AArch64GenProEpilog::GeneratePushRegs() and AArch64GenProEpilog::GeneratePopRegs() */ RegOperand &br = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(baseRegNum, bitLen, kRegTyInt); - if (aarchCGFunc.GetSplitBaseOffset() == 0) { - aarchCGFunc.SetSplitBaseOffset(offsetVal); /* remember the offset; don't forget to clear it */ - ImmOperand &immAddEnd = aarchCGFunc.CreateImmOperand(offsetVal, k64BitSize, true); - RegOperand *origBaseReg = mo.GetBaseRegister(); - aarchCGFunc.SelectAdd(br, *origBaseReg, immAddEnd, PTY_i64); - } - offsetVal = offsetVal - aarchCGFunc.GetSplitBaseOffset(); - return &aarchCGFunc.CreateReplacementMemOperand(bitLen, br, offsetVal); + ImmOperand &immAddEnd = aarchCGFunc.CreateImmOperand(offsetVal, k64BitSize, true); + RegOperand *origBaseReg = mo.GetBaseRegister(); + aarchCGFunc.SelectAdd(br, *origBaseReg, immAddEnd, PTY_i64); + + return &aarchCGFunc.CreateReplacementMemOperand(bitLen, br, 0); } void AArch64GenProEpilog::AppendInstructionPushPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, @@ -874,61 +308,46 @@ void AArch64GenProEpilog::AppendInstructionPushPair(CGFunc &cgFunc, AArch64reg r { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopPair]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - Operand *o2 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerSize() * kBitsPerByte); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + Operand *o2 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerBitSize()); - uint32 dataSize = GetPointerSize() * kBitsPerByte; + uint32 dataSize = GetPointerBitSize(); CHECK_FATAL(offset >= 0, "offset must >= 0"); if (offset > kStpLdpImm64UpperBound) { o2 = SplitStpLdpOffsetForCalleeSavedWithAddInstruction(cgFunc, *static_cast(o2), dataSize, R16); } Insn &pushInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + // Identify that the instruction is not alias with any other memory instructions. + auto *memDefUse = cgFunc.GetFuncScopeAllocator()->New(*cgFunc.GetFuncScopeAllocator()); + memDefUse->SetIndependent(); + pushInsn.SetReferenceOsts(memDefUse); std::string comment = "SAVE CALLEE REGISTER PAIR"; pushInsn.SetComment(comment); AppendInstructionTo(pushInsn, cgFunc); - - /* Append CFi code */ - if (cgFunc.GenCfi() && !CGOptions::IsNoCalleeCFI()) { - int32 stackFrameSize = - static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); - stackFrameSize -= (static_cast(cgFunc.GetMemlayout()->SizeOfArgsToStackPass()) + - cgFunc.GetFunction().GetFrameReseverdSlot()); - int32 cfiOffset = stackFrameSize - offset; - BB *curBB = cgFunc.GetCurBB(); - Insn *newInsn = curBB->InsertInsnAfter(pushInsn, aarchCGFunc.CreateCfiOffsetInsn(reg0, -cfiOffset, k64BitSize)); - curBB->InsertInsnAfter(*newInsn, - aarchCGFunc.CreateCfiOffsetInsn(reg1, -cfiOffset + kOffset8MemPos, k64BitSize)); - } } void AArch64GenProEpilog::AppendInstructionPushSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int32 offset) { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopSingle]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg, GetPointerSize() * kBitsPerByte, rty); - Operand *o1 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerSize() * kBitsPerByte); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg, GetPointerBitSize(), rty); + Operand *o1 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerBitSize()); MemOperand *aarchMemO1 = static_cast(o1); - uint32 dataSize = GetPointerSize() * kBitsPerByte; + uint32 dataSize = GetPointerBitSize(); if (aarchMemO1->GetMemVaryType() == kNotVary && aarchCGFunc.IsImmediateOffsetOutOfRange(*aarchMemO1, dataSize)) { - o1 = &aarchCGFunc.SplitOffsetWithAddInstruction(*aarchMemO1, dataSize, R9); + o1 = &aarchCGFunc.SplitOffsetWithAddInstruction(*aarchMemO1, dataSize, R16); } Insn &pushInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, *o1); + // Identify that the instruction is not alias with any other memory instructions. + auto *memDefUse = cgFunc.GetFuncScopeAllocator()->New(*cgFunc.GetFuncScopeAllocator()); + memDefUse->SetIndependent(); + pushInsn.SetReferenceOsts(memDefUse); std::string comment = "SAVE CALLEE REGISTER"; pushInsn.SetComment(comment); AppendInstructionTo(pushInsn, cgFunc); - - /* Append CFI code */ - if (cgFunc.GenCfi() && !CGOptions::IsNoCalleeCFI()) { - int32 stackFrameSize = - static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); - stackFrameSize -= (static_cast(cgFunc.GetMemlayout()->SizeOfArgsToStackPass()) + - cgFunc.GetFunction().GetFrameReseverdSlot()); - int32 cfiOffset = stackFrameSize - offset; - cgFunc.GetCurBB()->InsertInsnAfter(pushInsn, aarchCGFunc.CreateCfiOffsetInsn(reg, -cfiOffset, k64BitSize)); - } } Insn &AArch64GenProEpilog::AppendInstructionForAllocateOrDeallocateCallFrame(int64 fpToSpDistance, AArch64reg reg0, @@ -945,10 +364,12 @@ Insn &AArch64GenProEpilog::AppendInstructionForAllocateOrDeallocateCallFrame(int } if (fpToSpDistance <= kStrLdrImm64UpperBound - kOffset8MemPos) { mOp = isAllocate ? pushPopOps[kRegsPushOp][rty][kPushPopSingle] : pushPopOps[kRegsPopOp][rty][kPushPopSingle]; - RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, size * kBitsPerByte, rty); MemOperand *o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), size * kBitsPerByte); - Insn &insn1 = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, *o2); - AppendInstructionTo(insn1, cgFunc); + if (storeFP) { + RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, size * kBitsPerByte, rty); + Insn &insn1 = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, *o2); + AppendInstructionTo(insn1, cgFunc); + } RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, size * kBitsPerByte, rty); o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance + size), size * kBitsPerByte); Insn &insn2 = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, *o2); @@ -958,11 +379,13 @@ Insn &AArch64GenProEpilog::AppendInstructionForAllocateOrDeallocateCallFrame(int RegOperand &oo = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(R9, size * kBitsPerByte, kRegTyInt); ImmOperand &io1 = aarchCGFunc.CreateImmOperand(fpToSpDistance, k64BitSize, true); aarchCGFunc.SelectCopyImm(oo, io1, PTY_i64); - RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, size * kBitsPerByte, rty); RegOperand &rsp = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, size * kBitsPerByte, kRegTyInt); MemOperand *mo = aarchCGFunc.CreateMemOperand(MemOperand::kAddrModeBOrX, size * kBitsPerByte, rsp, oo, 0); - Insn &insn1 = cgFunc.GetInsnBuilder()->BuildInsn(isAllocate ? MOP_xstr : MOP_xldr, o0, *mo); - AppendInstructionTo(insn1, cgFunc); + if (storeFP) { + RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, size * kBitsPerByte, rty); + Insn &insn1 = cgFunc.GetInsnBuilder()->BuildInsn(isAllocate ? MOP_xstr : MOP_xldr, o0, *mo); + AppendInstructionTo(insn1, cgFunc); + } ImmOperand &io2 = aarchCGFunc.CreateImmOperand(size, k64BitSize, true); aarchCGFunc.SelectAdd(oo, oo, io2, PTY_i64); RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, size * kBitsPerByte, rty); @@ -978,24 +401,23 @@ Insn &AArch64GenProEpilog::CreateAndAppendInstructionForAllocateCallFrame(int64 { auto &aarchCGFunc = static_cast(cgFunc); CG *currCG = cgFunc.GetCG(); - MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopPair]; + MOperator mOp = (storeFP || fpToSpDistance > kStrLdrPerPostUpperBound) + ? pushPopOps[kRegsPushOp][rty][kPushPopPair] + : pushPopOps[kRegsPushOp][rty][kPushPopSingle]; Insn *allocInsn = nullptr; if (fpToSpDistance > kStpLdpImm64UpperBound) { allocInsn = &AppendInstructionForAllocateOrDeallocateCallFrame(fpToSpDistance, reg0, reg1, rty, true); } else { - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - Operand *o2 = - aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerSize() * kBitsPerByte); - allocInsn = &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + Operand *o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerBitSize()); + allocInsn = (storeFP || fpToSpDistance > kStrLdrPerPostUpperBound) + ? &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2) + : &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, *o2); AppendInstructionTo(*allocInsn, cgFunc); } - if (currCG->NeedInsertInstrumentationFunction()) { - aarchCGFunc.AppendCall(*currCG->GetInstrumentationFunction()); - } else if (currCG->InstrumentWithDebugTraceCall()) { + if (currCG->InstrumentWithDebugTraceCall()) { aarchCGFunc.AppendCall(*currCG->GetDebugTraceEnterFunction()); - } else if (currCG->InstrumentWithProfile()) { - aarchCGFunc.AppendCall(*currCG->GetProfileFunction()); } return *allocInsn; } @@ -1022,7 +444,6 @@ void AArch64GenProEpilog::AppendInstructionAllocateCallFrame(AArch64reg reg0, AA */ bool useStpSub = false; int64 offset = 0; - int32 cfiOffset = 0; if (!cgFunc.HasVLAOrAlloca() && fpToSpDistance > 0) { /* * stack_frame_size == size of formal parameters + callee-saved (including FP/RL) @@ -1035,7 +456,6 @@ void AArch64GenProEpilog::AppendInstructionAllocateCallFrame(AArch64reg reg0, AA Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectSub(spOpnd, spOpnd, immOpnd, PTY_u64); ipoint = cgFunc.GetCurBB()->GetLastInsn(); - cfiOffset = stackFrameSize; } else { if (stackFrameSize > kStpLdpImm64UpperBound) { useStpSub = true; @@ -1044,56 +464,34 @@ void AArch64GenProEpilog::AppendInstructionAllocateCallFrame(AArch64reg reg0, AA } else { offset = stackFrameSize; } - MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopPair]; - RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - MemOperand &o2 = - aarchCGFunc.CreateCallFrameOperand(static_cast(-offset), GetPointerSize() * kBitsPerByte); - ipoint = &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2); + MOperator mOp = (storeFP || offset > kStrLdrPerPostUpperBound) ? pushPopOps[kRegsPushOp][rty][kPushPopPair] + : pushPopOps[kRegsPushOp][rty][kPushPopSingle]; + RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + MemOperand &o2 = aarchCGFunc.CreateCallFrameOperand(static_cast(-offset), GetPointerBitSize()); + ipoint = (storeFP || offset > kStrLdrPerPostUpperBound) ? &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2) + : &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, o2); AppendInstructionTo(*ipoint, cgFunc); - cfiOffset = offset; - if (currCG->NeedInsertInstrumentationFunction()) { - aarchCGFunc.AppendCall(*currCG->GetInstrumentationFunction()); - } else if (currCG->InstrumentWithDebugTraceCall()) { + if (currCG->InstrumentWithDebugTraceCall()) { aarchCGFunc.AppendCall(*currCG->GetDebugTraceEnterFunction()); - } else if (currCG->InstrumentWithProfile()) { - aarchCGFunc.AppendCall(*currCG->GetProfileFunction()); } } - ipoint = InsertCFIDefCfaOffset(cfiOffset, *ipoint); + ipoint->SetStackDef(true); if (!cgFunc.HasVLAOrAlloca() && fpToSpDistance > 0) { CHECK_FATAL(!useStpSub, "Invalid assumption"); ipoint = &CreateAndAppendInstructionForAllocateCallFrame(fpToSpDistance, reg0, reg1, rty); } + CHECK_FATAL(ipoint != nullptr, "ipoint should not be nullptr at this point"); if (useStpSub) { Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectSub(spOpnd, spOpnd, immOpnd, PTY_u64); ipoint = cgFunc.GetCurBB()->GetLastInsn(); aarchCGFunc.SetUsedStpSubPairForCallFrameAllocation(true); - } - - CHECK_FATAL(ipoint != nullptr, "ipoint should not be nullptr at this point"); - int32 cfiOffsetSecond = 0; - if (useStpSub) { - cfiOffsetSecond = stackFrameSize; - ipoint = InsertCFIDefCfaOffset(cfiOffsetSecond, *ipoint); - } - cfiOffsetSecond = GetOffsetFromCFA(); - if (!cgFunc.HasVLAOrAlloca()) { - cfiOffsetSecond -= fpToSpDistance; - } - if (cgFunc.GenCfi()) { - BB *curBB = cgFunc.GetCurBB(); - if (useFP) { - ipoint = curBB->InsertInsnAfter( - *ipoint, aarchCGFunc.CreateCfiOffsetInsn(stackBaseReg, -cfiOffsetSecond, k64BitSize)); - } - curBB->InsertInsnAfter(*ipoint, - aarchCGFunc.CreateCfiOffsetInsn(RLR, -cfiOffsetSecond + kOffset8MemPos, k64BitSize)); + ipoint->SetStackDef(true); } } @@ -1111,22 +509,15 @@ void AArch64GenProEpilog::AppendInstructionAllocateCallFrameDebug(AArch64reg reg (cgFunc.GetMemlayout()->SizeOfArgsToStackPass() + cgFunc.GetFunction().GetFrameReseverdSlot()); Insn *ipoint = nullptr; - int32 cfiOffset = 0; if (fpToSpDistance > 0) { Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectSub(spOpnd, spOpnd, immOpnd, PTY_u64); ipoint = cgFunc.GetCurBB()->GetLastInsn(); - cfiOffset = stackFrameSize; - (void)InsertCFIDefCfaOffset(cfiOffset, *ipoint); - if (cgFunc.GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) { - fpToSpDistance -= (kDivide2 * k8ByteSize); - } + ipoint->SetStackDef(true); ipoint = &CreateAndAppendInstructionForAllocateCallFrame(fpToSpDistance, reg0, reg1, rty); CHECK_FATAL(ipoint != nullptr, "ipoint should not be nullptr at this point"); - cfiOffset = GetOffsetFromCFA(); - cfiOffset -= fpToSpDistance; } else { bool useStpSub = false; @@ -1136,46 +527,35 @@ void AArch64GenProEpilog::AppendInstructionAllocateCallFrameDebug(AArch64reg reg ImmOperand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectSub(spOpnd, spOpnd, immOpnd, PTY_u64); ipoint = cgFunc.GetCurBB()->GetLastInsn(); - cfiOffset = stackFrameSize; - ipoint = InsertCFIDefCfaOffset(cfiOffset, *ipoint); + ipoint->SetStackDef(true); } else { - MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopPair]; - RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - MemOperand &o2 = aarchCGFunc.CreateCallFrameOperand(-stackFrameSize, GetPointerSize() * kBitsPerByte); - ipoint = &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2); + MOperator mOp = (storeFP || stackFrameSize > kStrLdrPerPostUpperBound) + ? pushPopOps[kRegsPushOp][rty][kPushPopPair] + : pushPopOps[kRegsPushOp][rty][kPushPopSingle]; + RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + MemOperand &o2 = aarchCGFunc.CreateCallFrameOperand(-stackFrameSize, GetPointerBitSize()); + ipoint = (storeFP || stackFrameSize > kStrLdrPerPostUpperBound) + ? &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2) + : &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, o2); AppendInstructionTo(*ipoint, cgFunc); - cfiOffset = stackFrameSize; - ipoint = InsertCFIDefCfaOffset(cfiOffset, *ipoint); + ipoint->SetStackDef(true); } if (useStpSub) { - MOperator mOp = pushPopOps[kRegsPushOp][rty][kPushPopPair]; - RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - MemOperand *o2 = aarchCGFunc.CreateStackMemOpnd(RSP, 0, GetPointerSize() * kBitsPerByte); - ipoint = &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + MOperator mOp = + storeFP ? pushPopOps[kRegsPushOp][rty][kPushPopPair] : pushPopOps[kRegsPushOp][rty][kPushPopSingle]; + RegOperand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + RegOperand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + MemOperand *o2 = aarchCGFunc.CreateStackMemOpnd(RSP, 0, GetPointerBitSize()); + ipoint = storeFP ? &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2) + : &cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, *o2); AppendInstructionTo(*ipoint, cgFunc); } - if (currCG->NeedInsertInstrumentationFunction()) { - aarchCGFunc.AppendCall(*currCG->GetInstrumentationFunction()); - } else if (currCG->InstrumentWithDebugTraceCall()) { + if (currCG->InstrumentWithDebugTraceCall()) { aarchCGFunc.AppendCall(*currCG->GetDebugTraceEnterFunction()); - } else if (currCG->InstrumentWithProfile()) { - aarchCGFunc.AppendCall(*currCG->GetProfileFunction()); } - - CHECK_FATAL(ipoint != nullptr, "ipoint should not be nullptr at this point"); - cfiOffset = GetOffsetFromCFA(); - } - if (cgFunc.GenCfi()) { - BB *curBB = cgFunc.GetCurBB(); - if (useFP) { - ipoint = - curBB->InsertInsnAfter(*ipoint, aarchCGFunc.CreateCfiOffsetInsn(stackBaseReg, -cfiOffset, k64BitSize)); - } - curBB->InsertInsnAfter(*ipoint, aarchCGFunc.CreateCfiOffsetInsn(RLR, -cfiOffset + kOffset8MemPos, k64BitSize)); } } @@ -1194,8 +574,9 @@ void AArch64GenProEpilog::GeneratePushRegs() { auto &aarchCGFunc = static_cast(cgFunc); CG *currCG = cgFunc.GetCG(); - const MapleVector ®sToSave = - (!CGOptions::DoRegSavesOpt()) ? aarchCGFunc.GetCalleeSavedRegs() : aarchCGFunc.GetProEpilogSavedRegs(); + const MapleVector ®sToSave = (aarchCGFunc.GetProEpilogSavedRegs().empty()) + ? aarchCGFunc.GetCalleeSavedRegs() + : aarchCGFunc.GetProEpilogSavedRegs(); CHECK_FATAL(!regsToSave.empty(), "FP/LR not added to callee-saved list?"); @@ -1239,33 +620,24 @@ void AArch64GenProEpilog::GeneratePushRegs() aarchCGFunc.SelectAdd(fpOpnd, spOpnd, *immOpnd, PTY_u64); } cgFunc.GetCurBB()->GetLastInsn()->SetFrameDef(true); - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiDefCfaInsn( - stackBaseReg, - static_cast(cgFunc.GetMemlayout())->RealStackFrameSize() - fpToSpDistance, - k64BitSize)); - } } else { aarchCGFunc.SelectCopy(fpOpnd, PTY_u64, spOpnd, PTY_u64); cgFunc.GetCurBB()->GetLastInsn()->SetFrameDef(true); - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn( - cgFunc.GetInsnBuilder() - ->BuildCfiInsn(cfi::OP_CFI_def_cfa_register) - .AddOpndChain(aarchCGFunc.CreateCfiRegOperand(stackBaseReg, k64BitSize))); - } } } MapleVector::const_iterator it = regsToSave.begin(); - /* skip the first two registers */ - CHECK_FATAL(*it == RFP, "The first callee saved reg is expected to be RFP"); - ++it; + // skip the RFP & RLR + if (*it == RFP) { + ++it; + } CHECK_FATAL(*it == RLR, "The second callee saved reg is expected to be RLR"); ++it; + // callee save offset + // fp - callee save base = RealStackFrameSize - [GR,16] - [VR,16] - [cold,16] - [callee] - stack protect + 16(fplr) AArch64MemLayout *memLayout = static_cast(cgFunc.GetMemlayout()); - int32 offset; + int32 offset = 0; if (cgFunc.GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc) { offset = static_cast((memLayout->RealStackFrameSize() - aarchCGFunc.SizeOfCalleeSaved()) - memLayout->GetSizeOfLocals()); @@ -1279,18 +651,23 @@ void AArch64GenProEpilog::GeneratePushRegs() offset -= kAarch64StackPtrAlignment; } - if (cgFunc.GetMirModule().IsCModule() && cgFunc.GetFunction().GetAttr(FUNCATTR_varargs)) { + if (cgFunc.GetMirModule().IsCModule() && cgFunc.GetFunction().GetAttr(FUNCATTR_varargs) && + cgFunc.GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) { /* GR/VR save areas are above the callee save area */ AArch64MemLayout *ml = static_cast(cgFunc.GetMemlayout()); auto saveareasize = static_cast(RoundUp(ml->GetSizeOfGRSaveArea(), GetPointerSize() * k2BitSize) + RoundUp(ml->GetSizeOfVRSaveArea(), GetPointerSize() * k2BitSize)); offset -= saveareasize; } + offset -= static_cast(RoundUp(memLayout->GetSizeOfSegCold(), k16BitSize)); std::vector> calleeRegAndOffsetVec; for (; it != regsToSave.end(); ++it) { AArch64reg reg = *it; - CHECK_FATAL(reg != RFP, "stray RFP in callee_saved_list?"); + // skip the RFP + if (reg == RFP) { + continue; + } CHECK_FATAL(reg != RLR, "stray RLR in callee_saved_list?"); RegType regType = AArch64isa::IsGPRegister(reg) ? kRegTyInt : kRegTyFloat; AArch64reg &firstHalf = AArch64isa::IsGPRegister(reg) ? intRegFirstHalf : fpRegFirstHalf; @@ -1321,13 +698,6 @@ void AArch64GenProEpilog::GeneratePushRegs() AArch64isa::GetNextOffsetCalleeSaved(offset); } - /* - * in case we split stp/ldp instructions, - * so that we generate a load-into-base-register instruction - * for pop pairs as well. - */ - aarchCGFunc.SetSplitBaseOffset(0); - const auto &emitMemoryManager = CGOptions::GetInstance().GetEmitMemoryManager(); if (emitMemoryManager.codeSpace != nullptr) { emitMemoryManager.funcCalleeOffsetSaver(emitMemoryManager.codeSpace, cgFunc.GetName(), calleeRegAndOffsetVec); @@ -1342,6 +712,7 @@ void AArch64GenProEpilog::GeneratePushRegs() void AArch64GenProEpilog::GeneratePushUnnamedVarargRegs() { auto &aarchCGFunc = static_cast(cgFunc); + uint32 offset; if (cgFunc.GetMirModule().IsCModule() && cgFunc.GetFunction().GetAttr(FUNCATTR_varargs)) { AArch64MemLayout *memlayout = static_cast(cgFunc.GetMemlayout()); uint8 size; @@ -1351,34 +722,25 @@ void AArch64GenProEpilog::GeneratePushUnnamedVarargRegs() size = GetPointerSize(); } uint32 dataSizeBits = size * kBitsPerByte; - uint32 offset; if (cgFunc.GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) { offset = static_cast(memlayout->GetGRSaveAreaBaseLoc()); /* SP reference */ - if (memlayout->GetSizeOfGRSaveArea() % kAarch64StackPtrAlignment) { - offset += size; /* End of area should be aligned. Hole between VR and GR area */ - } } else { - offset = (UINT32_MAX - memlayout->GetSizeOfGRSaveArea()) + 1; /* FP reference */ - if (memlayout->GetSizeOfGRSaveArea() % kAarch64StackPtrAlignment) { - offset -= size; - } + offset = static_cast(memlayout->GetGRSaveAreaBaseLoc()) + memlayout->SizeOfArgsToStackPass(); + } + if ((memlayout->GetSizeOfGRSaveArea() % kAarch64StackPtrAlignment) != 0) { + offset += size; /* End of area should be aligned. Hole between VR and GR area */ } - uint32 grSize = (UINT32_MAX - offset) + 1; - uint32 start_regno = k8BitSize - (memlayout->GetSizeOfGRSaveArea() / size); - DEBUG_ASSERT(start_regno <= k8BitSize, "Incorrect starting GR regno for GR Save Area"); - for (uint32 i = start_regno + static_cast(R0); i < static_cast(R8); i++) { + CHECK_FATAL(size != 0, "Divisor cannot be zero"); + uint32 startRegno = k8BitSize - (memlayout->GetSizeOfGRSaveArea() / size); + DEBUG_ASSERT(startRegno <= k8BitSize, "Incorrect starting GR regno for GR Save Area"); + for (uint32 i = startRegno + static_cast(R0); i < static_cast(R8); i++) { uint32 tmpOffset = 0; if (CGOptions::IsBigEndian()) { if ((dataSizeBits >> k8BitShift) < k8BitSize) { tmpOffset += k8BitSize - (dataSizeBits >> k8BitShift); } } - Operand *stackLoc; - if (cgFunc.GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) { - stackLoc = &aarchCGFunc.CreateStkTopOpnd(offset + tmpOffset, dataSizeBits); - } else { - stackLoc = aarchCGFunc.GenLmbcFpMemOperand(offset, size); - } + Operand *stackLoc = &aarchCGFunc.CreateStkTopOpnd(offset + tmpOffset, dataSizeBits); RegOperand ® = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(static_cast(i), k64BitSize, kRegTyInt); Insn &inst = @@ -1390,27 +752,23 @@ void AArch64GenProEpilog::GeneratePushUnnamedVarargRegs() if (cgFunc.GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) { offset = static_cast(memlayout->GetVRSaveAreaBaseLoc()); } else { - offset = (UINT32_MAX - (memlayout->GetSizeOfVRSaveArea() + grSize)) + 1; + offset = static_cast(memlayout->GetVRSaveAreaBaseLoc()) + memlayout->SizeOfArgsToStackPass(); } - start_regno = k8BitSize - (memlayout->GetSizeOfVRSaveArea() / (size * k2BitSize)); - DEBUG_ASSERT(start_regno <= k8BitSize, "Incorrect starting GR regno for VR Save Area"); - for (uint32 i = start_regno + static_cast(V0); i < static_cast(V8); i++) { + startRegno = k8BitSize - (memlayout->GetSizeOfVRSaveArea() / (size * k2BitSize)); + DEBUG_ASSERT(startRegno <= k8BitSize, "Incorrect starting GR regno for VR Save Area"); + dataSizeBits = k128BitSize; + for (uint32 i = startRegno + static_cast(V0); i < static_cast(V8); i++) { uint32 tmpOffset = 0; if (CGOptions::IsBigEndian()) { if ((dataSizeBits >> k8BitShift) < k16BitSize) { tmpOffset += k16BitSize - (dataSizeBits >> k8BitShift); } } - Operand *stackLoc; - if (cgFunc.GetMirModule().GetFlavor() != MIRFlavor::kFlavorLmbc) { - stackLoc = &aarchCGFunc.CreateStkTopOpnd(offset + tmpOffset, dataSizeBits); - } else { - stackLoc = aarchCGFunc.GenLmbcFpMemOperand(offset, size); - } - RegOperand ® = - aarchCGFunc.GetOrCreatePhysicalRegisterOperand(static_cast(i), k64BitSize, kRegTyFloat); + Operand *stackLoc = &aarchCGFunc.CreateStkTopOpnd(offset + tmpOffset, dataSizeBits); + RegOperand ® = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(static_cast(i), + dataSizeBits, kRegTyFloat); Insn &inst = - cgFunc.GetInsnBuilder()->BuildInsn(aarchCGFunc.PickStInsn(dataSizeBits, PTY_f64), reg, *stackLoc); + cgFunc.GetInsnBuilder()->BuildInsn(aarchCGFunc.PickStInsn(dataSizeBits, PTY_f128), reg, *stackLoc); cgFunc.GetCurBB()->AppendInsn(inst); offset += (size * k2BitSize); } @@ -1441,26 +799,28 @@ void AArch64GenProEpilog::AppendInstructionStackCheck(AArch64reg reg, RegType rt void AArch64GenProEpilog::GenerateProlog(BB &bb) { + if (!cgFunc.GetHasProEpilogue()) { + return; + } + if (PROEPILOG_DUMP) { + LogInfo::MapleLogger() << "generate prolog at BB " << bb.GetId() << "\n"; + } + + AddStackGuard(bb); auto &aarchCGFunc = static_cast(cgFunc); CG *currCG = cgFunc.GetCG(); BB *formerCurBB = cgFunc.GetCurBB(); aarchCGFunc.GetDummyBB()->ClearInsns(); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(true); cgFunc.SetCurBB(*aarchCGFunc.GetDummyBB()); - if (!cgFunc.GetHasProEpilogue()) { - return; - } // insert .loc for function - if (currCG->GetCGOptions().WithLoc() && - (!currCG->GetMIRModule()->IsCModule() || currCG->GetMIRModule()->IsWithDbgInfo())) { + if (currCG->GetCGOptions().WithLoc() && (!currCG->GetMIRModule()->IsCModule())) { MIRFunction *func = &cgFunc.GetFunction(); MIRSymbol *fSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(func->GetStIdx().Idx()); if (currCG->GetCGOptions().WithSrc()) { uint32 tempmaxsize = static_cast(currCG->GetMIRModule()->GetSrcFileInfo().size()); uint32 endfilenum = currCG->GetMIRModule()->GetSrcFileInfo()[tempmaxsize - 1].second; if (fSym->GetSrcPosition().FileNum() != 0 && fSym->GetSrcPosition().FileNum() <= endfilenum) { - Operand *o0 = cgFunc.CreateDbgImmOperand(fSym->GetSrcPosition().FileNum()); int64_t lineNum = fSym->GetSrcPosition().LineNum(); if (lineNum == 0) { if (cgFunc.GetFunction().GetAttr(FUNCATTR_native)) { @@ -1469,21 +829,18 @@ void AArch64GenProEpilog::GenerateProlog(BB &bb) lineNum = 0xffffd; } } - Operand *o1 = cgFunc.CreateDbgImmOperand(lineNum); Insn &loc = - cgFunc.GetInsnBuilder()->BuildDbgInsn(mpldbg::OP_DBG_loc).AddOpndChain(*o0).AddOpndChain(*o1); + cgFunc.BuildLocInsn(fSym->GetSrcPosition().FileNum(), lineNum, fSym->GetSrcPosition().Column()); cgFunc.GetCurBB()->AppendInsn(loc); } } else { - Operand *o0 = cgFunc.CreateDbgImmOperand(1); - Operand *o1 = cgFunc.CreateDbgImmOperand(fSym->GetSrcPosition().MplLineNum()); - Insn &loc = cgFunc.GetInsnBuilder()->BuildDbgInsn(mpldbg::OP_DBG_loc).AddOpndChain(*o0).AddOpndChain(*o1); - cgFunc.GetCurBB()->AppendInsn(loc); + cgFunc.GetCurBB()->AppendInsn(cgFunc.BuildLocInsn(1, fSym->GetSrcPosition().MplLineNum(), 0)); } } - const MapleVector ®sToSave = - (!CGOptions::DoRegSavesOpt()) ? aarchCGFunc.GetCalleeSavedRegs() : aarchCGFunc.GetProEpilogSavedRegs(); + const MapleVector ®sToSave = (aarchCGFunc.GetProEpilogSavedRegs().empty()) + ? aarchCGFunc.GetCalleeSavedRegs() + : aarchCGFunc.GetProEpilogSavedRegs(); if (!regsToSave.empty()) { /* * Among other things, push the FP & LR pair. @@ -1502,9 +859,7 @@ void AArch64GenProEpilog::GenerateProlog(BB &bb) } Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectSub(spOpnd, spOpnd, immOpnd, PTY_u64); - - int32 offset = stackFrameSize; - (void)InsertCFIDefCfaOffset(offset, *(cgFunc.GetCurBB()->GetLastInsn())); + cgFunc.GetCurBB()->GetLastInsn()->SetStackDef(true); } if (currCG->GenerateVerboseCG()) { cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCommentInsn("copy SP to FP")); @@ -1525,21 +880,9 @@ void AArch64GenProEpilog::GenerateProlog(BB &bb) } aarchCGFunc.SelectAdd(fpOpnd, spOpnd, *immOpnd, PTY_u64); cgFunc.GetCurBB()->GetLastInsn()->SetFrameDef(true); - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiDefCfaInsn( - stackBaseReg, - static_cast(cgFunc.GetMemlayout())->RealStackFrameSize() - fpToSpDistance, - k64BitSize)); - } } else { aarchCGFunc.SelectCopy(fpOpnd, PTY_u64, spOpnd, PTY_u64); cgFunc.GetCurBB()->GetLastInsn()->SetFrameDef(true); - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn( - cgFunc.GetInsnBuilder() - ->BuildCfiInsn(cfi::OP_CFI_def_cfa_register) - .AddOpndChain(aarchCGFunc.CreateCfiRegOperand(stackBaseReg, k64BitSize))); - } } } } @@ -1549,11 +892,21 @@ void AArch64GenProEpilog::GenerateProlog(BB &bb) } bb.InsertAtBeginning(*aarchCGFunc.GetDummyBB()); cgFunc.SetCurBB(*formerCurBB); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(false); } void AArch64GenProEpilog::GenerateRet(BB &bb) { + auto *lastInsn = bb.GetLastMachineInsn(); + if (lastInsn != nullptr && (lastInsn->IsTailCall() || lastInsn->IsBranch())) { + return; + } + /* Insert the loc insn before ret insn + so that the breakpoint can break at the end of the block's reverse parenthesis line. */ + SrcPosition pos = cgFunc.GetFunction().GetScope()->GetRangeHigh(); + if (cgFunc.GetCG()->GetCGOptions().WithDwarf() && cgFunc.GetWithSrc() && cgFunc.GetMirModule().IsCModule() && + pos.FileNum() != 0) { + bb.AppendInsn(cgFunc.BuildLocInsn(pos.FileNum(), pos.LineNum(), pos.Column())); + } bb.AppendInsn(cgFunc.GetInsnBuilder()->BuildInsn(MOP_xret)); } @@ -1568,46 +921,33 @@ bool AArch64GenProEpilog::TestPredsOfRetBB(const BB &exitBB) (cgFunc.GetFunction().GetAttr(FUNCATTR_varargs) || ml->GetSizeOfLocals() > 0 || cgFunc.HasVLAOrAlloca())) { return false; } - for (auto tmpBB : exitBB.GetPreds()) { - Insn *firstInsn = tmpBB->GetFirstInsn(); - if ((firstInsn == nullptr || tmpBB->IsCommentBB()) && (!tmpBB->GetPreds().empty())) { - if (!TestPredsOfRetBB(*tmpBB)) { - return false; - } - } else { - Insn *lastInsn = tmpBB->GetLastInsn(); - if (lastInsn == nullptr) { - return false; - } - MOperator insnMop = lastInsn->GetMachineOpcode(); - if (insnMop != MOP_tail_call_opt_xbl && insnMop != MOP_tail_call_opt_xblr) { - return false; - } - } + const Insn *lastInsn = exitBB.GetLastInsn(); + while (lastInsn != nullptr && (!lastInsn->IsMachineInstruction() || lastInsn->IsPseudo())) { + lastInsn = lastInsn->GetPrev(); } - return true; + bool isTailCall = lastInsn == nullptr ? false : lastInsn->IsTailCall(); + return isTailCall; } void AArch64GenProEpilog::AppendInstructionPopSingle(CGFunc &cgFunc, AArch64reg reg, RegType rty, int32 offset) { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPopOp][rty][kPushPopSingle]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg, GetPointerSize() * kBitsPerByte, rty); - Operand *o1 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerSize() * kBitsPerByte); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg, GetPointerBitSize(), rty); + Operand *o1 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerBitSize()); MemOperand *aarchMemO1 = static_cast(o1); - uint32 dataSize = GetPointerSize() * kBitsPerByte; + uint32 dataSize = GetPointerBitSize(); if (aarchMemO1->GetMemVaryType() == kNotVary && aarchCGFunc.IsImmediateOffsetOutOfRange(*aarchMemO1, dataSize)) { - o1 = &aarchCGFunc.SplitOffsetWithAddInstruction(*aarchMemO1, dataSize, R9); + o1 = &aarchCGFunc.SplitOffsetWithAddInstruction(*aarchMemO1, dataSize, R16); } Insn &popInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, *o1); + // Identify that the instruction is not alias with any other memory instructions. + auto *memDefUse = cgFunc.GetFuncScopeAllocator()->New(*cgFunc.GetFuncScopeAllocator()); + memDefUse->SetIndependent(); + popInsn.SetReferenceOsts(memDefUse); popInsn.SetComment("RESTORE"); cgFunc.GetCurBB()->AppendInsn(popInsn); - - /* Append CFI code. */ - if (cgFunc.GenCfi() && !CGOptions::IsNoCalleeCFI()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(reg, k64BitSize)); - } } void AArch64GenProEpilog::AppendInstructionPopPair(CGFunc &cgFunc, AArch64reg reg0, AArch64reg reg1, RegType rty, @@ -1615,32 +955,30 @@ void AArch64GenProEpilog::AppendInstructionPopPair(CGFunc &cgFunc, AArch64reg re { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPopOp][rty][kPushPopPair]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); - Operand *o2 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerSize() * kBitsPerByte); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); + Operand *o2 = &aarchCGFunc.CreateStkTopOpnd(static_cast(offset), GetPointerBitSize()); - uint32 dataSize = GetPointerSize() * kBitsPerByte; + uint32 dataSize = GetPointerBitSize(); CHECK_FATAL(offset >= 0, "offset must >= 0"); if (offset > kStpLdpImm64UpperBound) { o2 = SplitStpLdpOffsetForCalleeSavedWithAddInstruction(cgFunc, static_cast(*o2), dataSize, R16); } Insn &popInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + // Identify that the instruction is not alias with any other memory instructions. + auto *memDefUse = cgFunc.GetFuncScopeAllocator()->New(*cgFunc.GetFuncScopeAllocator()); + memDefUse->SetIndependent(); + popInsn.SetReferenceOsts(memDefUse); popInsn.SetComment("RESTORE RESTORE"); cgFunc.GetCurBB()->AppendInsn(popInsn); - - /* Append CFI code */ - if (cgFunc.GenCfi() && !CGOptions::IsNoCalleeCFI()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(reg0, k64BitSize)); - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(reg1, k64BitSize)); - } } void AArch64GenProEpilog::AppendInstructionDeallocateCallFrame(AArch64reg reg0, AArch64reg reg1, RegType rty) { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPopOp][rty][kPushPopPair]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); int32 stackFrameSize = static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); int64 fpToSpDistance = cgFunc.GetMemlayout()->SizeOfArgsToStackPass() + cgFunc.GetFunction().GetFrameReseverdSlot(); @@ -1653,7 +991,7 @@ void AArch64GenProEpilog::AppendInstructionDeallocateCallFrame(AArch64reg reg0, Operand *o2 = nullptr; if (!cgFunc.HasVLAOrAlloca() && fpToSpDistance > 0) { - o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerSize() * kBitsPerByte); + o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerBitSize()); } else { if (stackFrameSize > kStpLdpImm64UpperBound) { useLdpAdd = true; @@ -1662,19 +1000,13 @@ void AArch64GenProEpilog::AppendInstructionDeallocateCallFrame(AArch64reg reg0, } else { offset = stackFrameSize; } - o2 = &aarchCGFunc.CreateCallFrameOperand(offset, GetPointerSize() * kBitsPerByte); + o2 = &aarchCGFunc.CreateCallFrameOperand(offset, GetPointerBitSize()); } if (useLdpAdd) { Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectAdd(spOpnd, spOpnd, immOpnd, PTY_u64); - if (cgFunc.GenCfi()) { - int64 cfiOffset = GetOffsetFromCFA(); - BB *curBB = cgFunc.GetCurBB(); - curBB->InsertInsnAfter(*(curBB->GetLastInsn()), - aarchCGFunc.CreateCfiDefCfaInsn(RSP, cfiOffset - stackFrameSize, k64BitSize)); - } } if (!cgFunc.HasVLAOrAlloca() && fpToSpDistance > 0) { @@ -1692,22 +1024,15 @@ void AArch64GenProEpilog::AppendInstructionDeallocateCallFrame(AArch64reg reg0, Insn &deallocInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); cgFunc.GetCurBB()->AppendInsn(deallocInsn); } - - if (cgFunc.GenCfi()) { - /* Append CFI restore */ - if (useFP) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(stackBaseReg, k64BitSize)); - } - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(RLR, k64BitSize)); - } + cgFunc.GetCurBB()->GetLastInsn()->SetStackRevert(true); } void AArch64GenProEpilog::AppendInstructionDeallocateCallFrameDebug(AArch64reg reg0, AArch64reg reg1, RegType rty) { auto &aarchCGFunc = static_cast(cgFunc); MOperator mOp = pushPopOps[kRegsPopOp][rty][kPushPopPair]; - Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerSize() * kBitsPerByte, rty); - Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerSize() * kBitsPerByte, rty); + Operand &o0 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg0, GetPointerBitSize(), rty); + Operand &o1 = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(reg1, GetPointerBitSize(), rty); int32 stackFrameSize = static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()); int64 fpToSpDistance = cgFunc.GetMemlayout()->SizeOfArgsToStackPass() + cgFunc.GetFunction().GetFrameReseverdSlot(); @@ -1717,58 +1042,49 @@ void AArch64GenProEpilog::AppendInstructionDeallocateCallFrameDebug(AArch64reg r */ bool isLmbc = (cgFunc.GetMirModule().GetFlavor() == MIRFlavor::kFlavorLmbc); if (cgFunc.HasVLAOrAlloca() || fpToSpDistance == 0 || isLmbc) { - int lmbcOffset = 0; + int32 lmbcOffset = 0; if (!isLmbc) { stackFrameSize -= fpToSpDistance; } else { lmbcOffset = fpToSpDistance - (kDivide2 * k8ByteSize); } if (stackFrameSize > kStpLdpImm64UpperBound || isLmbc) { - Operand *o2; - o2 = aarchCGFunc.CreateStackMemOpnd(RSP, (isLmbc ? lmbcOffset : 0), GetPointerSize() * kBitsPerByte); - Insn &deallocInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + Operand *o2 = aarchCGFunc.CreateStackMemOpnd(RSP, (isLmbc ? lmbcOffset : 0), GetPointerBitSize()); + mOp = storeFP ? pushPopOps[kRegsPopOp][rty][kPushPopPair] : pushPopOps[kRegsPopOp][rty][kPushPopSingle]; + Insn &deallocInsn = storeFP ? cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2) + : cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, *o2); cgFunc.GetCurBB()->AppendInsn(deallocInsn); - if (cgFunc.GenCfi()) { - /* Append CFI restore */ - if (useFP) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(stackBaseReg, k64BitSize)); - } - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(RLR, k64BitSize)); - } Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectAdd(spOpnd, spOpnd, immOpnd, PTY_u64); } else { - MemOperand &o2 = aarchCGFunc.CreateCallFrameOperand(stackFrameSize, GetPointerSize() * kBitsPerByte); - Insn &deallocInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2); + MemOperand &o2 = aarchCGFunc.CreateCallFrameOperand(stackFrameSize, GetPointerBitSize()); + mOp = (storeFP || stackFrameSize > kStrLdrPerPostUpperBound) ? pushPopOps[kRegsPopOp][rty][kPushPopPair] + : pushPopOps[kRegsPopOp][rty][kPushPopSingle]; + Insn &deallocInsn = (storeFP || stackFrameSize > kStrLdrPerPostUpperBound) + ? cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, o2) + : cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, o2); cgFunc.GetCurBB()->AppendInsn(deallocInsn); - if (cgFunc.GenCfi()) { - if (useFP) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(stackBaseReg, k64BitSize)); - } - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(RLR, k64BitSize)); - } } } else { Operand *o2; - o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerSize() * kBitsPerByte); + o2 = aarchCGFunc.CreateStackMemOpnd(RSP, static_cast(fpToSpDistance), GetPointerBitSize()); if (fpToSpDistance > kStpLdpImm64UpperBound) { (void)AppendInstructionForAllocateOrDeallocateCallFrame(fpToSpDistance, reg0, reg1, rty, false); } else { - Insn &deallocInsn = cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2); + mOp = (storeFP || fpToSpDistance > kStrLdrPerPostUpperBound) ? pushPopOps[kRegsPopOp][rty][kPushPopPair] + : pushPopOps[kRegsPopOp][rty][kPushPopSingle]; + Insn &deallocInsn = (storeFP || fpToSpDistance > kStrLdrPerPostUpperBound) + ? cgFunc.GetInsnBuilder()->BuildInsn(mOp, o0, o1, *o2) + : cgFunc.GetInsnBuilder()->BuildInsn(mOp, o1, *o2); cgFunc.GetCurBB()->AppendInsn(deallocInsn); } - if (cgFunc.GenCfi()) { - if (useFP) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(stackBaseReg, k64BitSize)); - } - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiRestoreInsn(RLR, k64BitSize)); - } Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectAdd(spOpnd, spOpnd, immOpnd, PTY_u64); } + cgFunc.GetCurBB()->GetLastInsn()->SetStackRevert(true); } void AArch64GenProEpilog::GeneratePopRegs() @@ -1776,8 +1092,9 @@ void AArch64GenProEpilog::GeneratePopRegs() auto &aarchCGFunc = static_cast(cgFunc); CG *currCG = cgFunc.GetCG(); - const MapleVector ®sToRestore = - (!CGOptions::DoRegSavesOpt()) ? aarchCGFunc.GetCalleeSavedRegs() : aarchCGFunc.GetProEpilogSavedRegs(); + const MapleVector ®sToRestore = (aarchCGFunc.GetProEpilogSavedRegs().empty()) + ? aarchCGFunc.GetCalleeSavedRegs() + : aarchCGFunc.GetProEpilogSavedRegs(); CHECK_FATAL(!regsToRestore.empty(), "FP/LR not added to callee-saved list?"); @@ -1796,8 +1113,10 @@ void AArch64GenProEpilog::GeneratePopRegs() * Make sure this is reflected when computing calleeSavedRegs.size() * skip the first two registers */ - CHECK_FATAL(*it == RFP, "The first callee saved reg is expected to be RFP"); - ++it; + // skip the RFP & RLR + if (*it == RFP) { + ++it; + } CHECK_FATAL(*it == RLR, "The second callee saved reg is expected to be RLR"); ++it; @@ -1825,13 +1144,17 @@ void AArch64GenProEpilog::GeneratePopRegs() offset -= saveareasize; } + offset -= static_cast(RoundUp(memLayout->GetSizeOfSegCold(), k16BitSize)); + /* * We are using a cleared dummy block; so insertPoint cannot be ret; * see GenerateEpilog() */ for (; it != regsToRestore.end(); ++it) { AArch64reg reg = *it; - CHECK_FATAL(reg != RFP, "stray RFP in callee_saved_list?"); + if (reg == RFP) { + continue; + } CHECK_FATAL(reg != RLR, "stray RLR in callee_saved_list?"); RegType regType = AArch64isa::IsGPRegister(reg) ? kRegTyInt : kRegTyFloat; @@ -1862,16 +1185,6 @@ void AArch64GenProEpilog::GeneratePopRegs() } else { AppendInstructionDeallocateCallFrameDebug(R29, RLR, kRegTyInt); } - - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiDefCfaInsn(RSP, 0, k64BitSize)); - } - /* - * in case we split stp/ldp instructions, - * so that we generate a load-into-base-register instruction - * for the next function, maybe? (seems not necessary, but...) - */ - aarchCGFunc.SetSplitBaseOffset(0); } void AArch64GenProEpilog::AppendJump(const MIRSymbol &funcSymbol) @@ -1881,23 +1194,38 @@ void AArch64GenProEpilog::AppendJump(const MIRSymbol &funcSymbol) cgFunc.GetCurBB()->AppendInsn(cgFunc.GetInsnBuilder()->BuildInsn(MOP_xuncond, targetOpnd)); } +void AArch64GenProEpilog::AppendBBtoEpilog(BB &epilogBB, BB &newBB) +{ + FOR_BB_INSNS(insn, &newBB) + { + insn->SetDoNotRemove(true); + } + auto *lastInsn = epilogBB.GetLastMachineInsn(); + if (lastInsn != nullptr && (lastInsn->IsTailCall() || lastInsn->IsBranch())) { + epilogBB.RemoveInsn(*lastInsn); + epilogBB.AppendBBInsns(newBB); + epilogBB.AppendInsn(*lastInsn); + } else { + epilogBB.AppendBBInsns(newBB); + } +} + void AArch64GenProEpilog::GenerateEpilog(BB &bb) { if (!cgFunc.GetHasProEpilogue()) { - if (bb.GetPreds().empty() || !TestPredsOfRetBB(bb)) { - GenerateRet(bb); - } return; } + if (PROEPILOG_DUMP) { + LogInfo::MapleLogger() << "generate epilog at BB " << bb.GetId() << "\n"; + } /* generate stack protected instruction */ - BB &epilogBB = GenStackGuardCheckInsn(bb); + GenStackGuardCheckInsn(bb); auto &aarchCGFunc = static_cast(cgFunc); CG *currCG = cgFunc.GetCG(); BB *formerCurBB = cgFunc.GetCurBB(); aarchCGFunc.GetDummyBB()->ClearInsns(); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(true); cgFunc.SetCurBB(*aarchCGFunc.GetDummyBB()); Operand &spOpnd = aarchCGFunc.GetOrCreatePhysicalRegisterOperand(RSP, k64BitSize, kRegTyInt); @@ -1907,26 +1235,9 @@ void AArch64GenProEpilog::GenerateEpilog(BB &bb) aarchCGFunc.SelectCopy(spOpnd, PTY_u64, fpOpnd, PTY_u64); } - /* Hack: exit bb should always be reachable, since we need its existance for ".cfi_remember_state" */ - if (&epilogBB != cgFunc.GetLastBB() && epilogBB.GetNext() != nullptr) { - BB *nextBB = epilogBB.GetNext(); - do { - if (nextBB == cgFunc.GetLastBB() || !nextBB->IsEmpty()) { - break; - } - nextBB = nextBB->GetNext(); - } while (nextBB != nullptr); - if (nextBB != nullptr && !nextBB->IsEmpty() && cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn(cgFunc.GetInsnBuilder()->BuildCfiInsn(cfi::OP_CFI_remember_state)); - cgFunc.GetCurBB()->SetHasCfi(); - nextBB->InsertInsnBefore(*nextBB->GetFirstInsn(), - cgFunc.GetInsnBuilder()->BuildCfiInsn(cfi::OP_CFI_restore_state)); - nextBB->SetHasCfi(); - } - } - - const MapleVector ®sToSave = - (!CGOptions::DoRegSavesOpt()) ? aarchCGFunc.GetCalleeSavedRegs() : aarchCGFunc.GetProEpilogSavedRegs(); + const MapleVector ®sToSave = (aarchCGFunc.GetProEpilogSavedRegs().empty()) + ? aarchCGFunc.GetCalleeSavedRegs() + : aarchCGFunc.GetProEpilogSavedRegs(); if (!regsToSave.empty()) { GeneratePopRegs(); } else { @@ -1944,9 +1255,7 @@ void AArch64GenProEpilog::GenerateEpilog(BB &bb) if (stackFrameSize > 0) { Operand &immOpnd = aarchCGFunc.CreateImmOperand(stackFrameSize, k32BitSize, true); aarchCGFunc.SelectAdd(spOpnd, spOpnd, immOpnd, PTY_u64); - if (cgFunc.GenCfi()) { - cgFunc.GetCurBB()->AppendInsn(aarchCGFunc.CreateCfiDefCfaInsn(RSP, 0, k64BitSize)); - } + aarchCGFunc.GetCurBB()->GetLastInsn()->SetStackRevert(true); } } } @@ -1955,14 +1264,12 @@ void AArch64GenProEpilog::GenerateEpilog(BB &bb) AppendJump(*(currCG->GetDebugTraceExitFunction())); } - GenerateRet(*(cgFunc.GetCurBB())); - epilogBB.AppendBBInsns(*cgFunc.GetCurBB()); + AppendBBtoEpilog(bb, *cgFunc.GetCurBB()); if (cgFunc.GetCurBB()->GetHasCfi()) { - epilogBB.SetHasCfi(); + bb.SetHasCfi(); } cgFunc.SetCurBB(*formerCurBB); - aarchCGFunc.GetDummyBB()->SetIsProEpilog(false); } void AArch64GenProEpilog::GenerateEpilogForCleanup(BB &bb) @@ -1978,141 +1285,33 @@ void AArch64GenProEpilog::GenerateEpilogForCleanup(BB &bb) } } -void AArch64GenProEpilog::ConvertToTailCalls(MapleSet &callInsnsMap) -{ - BB *exitBB = GetCurTailcallExitBB(); - - /* ExitBB is filled only by now. If exitBB has restore of SP indicating extra stack space has - been allocated, such as a function call with more than 8 args, argument with large aggr etc */ - FOR_BB_INSNS(insn, exitBB) { - if (insn->GetMachineOpcode() == MOP_xaddrri12 || insn->GetMachineOpcode() == MOP_xaddrri24) { - RegOperand ® = static_cast(insn->GetOperand(0)); - if (reg.GetRegisterNumber() == RSP) { - return; - } - } - } - - /* Replace all of the call insns. */ - for (Insn *callInsn : callInsnsMap) { - MOperator insnMop = callInsn->GetMachineOpcode(); - switch (insnMop) { - case MOP_xbl: { - callInsn->SetMOP(AArch64CG::kMd[MOP_tail_call_opt_xbl]); - break; - } - case MOP_xblr: { - callInsn->SetMOP(AArch64CG::kMd[MOP_tail_call_opt_xblr]); - break; - } - default: - CHECK_FATAL(false, "Internal error."); - break; - } - BB *bb = callInsn->GetBB(); - if (bb->GetKind() == BB::kBBGoto) { - bb->SetKind(BB::kBBFallthru); - if (bb->GetLastInsn()->GetMachineOpcode() == MOP_xuncond) { - bb->RemoveInsn(*bb->GetLastInsn()); - } - } - for (auto sBB : bb->GetSuccs()) { - bb->RemoveSuccs(*sBB); - sBB->RemovePreds(*bb); - break; - } - } - - /* copy instrs from exit block */ - for (Insn *callInsn : callInsnsMap) { - BB *toBB = callInsn->GetBB(); - BB *fromBB = exitBB; - if (toBB == fromBB) { - /* callsite also in the return exit block, just change the return to branch */ - Insn *lastInsn = toBB->GetLastInsn(); - if (lastInsn->GetMachineOpcode() == MOP_xret) { - Insn *newInsn = cgFunc.GetTheCFG()->CloneInsn(*callInsn); - toBB->ReplaceInsn(*lastInsn, *newInsn); - for (Insn *insn = callInsn->GetNextMachineInsn(); insn != newInsn; insn = insn->GetNextMachineInsn()) { - insn->SetDoNotRemove(true); - } - toBB->RemoveInsn(*callInsn); - return; - } - CHECK_FATAL(0, "Tailcall in incorrect block"); - } - FOR_BB_INSNS_SAFE(insn, fromBB, next) { - if (insn->IsCfiInsn() || (insn->IsMachineInstruction() && insn->GetMachineOpcode() != MOP_xret)) { - Insn *newInsn = cgFunc.GetTheCFG()->CloneInsn(*insn); - newInsn->SetDoNotRemove(true); - toBB->InsertInsnBefore(*callInsn, *newInsn); - } - } - } - - /* remove instrs in exit block */ - BB *bb = exitBB; - if (bb->GetPreds().size() > 0) { - return; /* exit block still needed by other non-tailcall blocks */ - } - Insn &junk = cgFunc.GetInsnBuilder()->BuildInsn(MOP_pseudo_none); - bb->AppendInsn(junk); - FOR_BB_INSNS_SAFE(insn, bb, next) { - if (insn->GetMachineOpcode() != MOP_pseudo_none) { - bb->RemoveInsn(*insn); - } - } -} - void AArch64GenProEpilog::Run() { CHECK_FATAL(cgFunc.GetFunction().GetBody()->GetFirst()->GetOpCode() == OP_label, "The first statement should be a label"); - NeedStackProtect(); - cgFunc.SetHasProEpilogue(NeedProEpilog()); - if (cgFunc.GetHasProEpilogue()) { - GenStackGuard(*(cgFunc.GetFirstBB())); - } - BB *proLog = nullptr; - if (cgFunc.GetCG()->DoPrologueEpilogue() && Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel2) { - /* There are some O2 dependent assumptions made */ - proLog = IsolateFastPath(*(cgFunc.GetFirstBB())); - } - + // update exitBB if (cgFunc.IsExitBBsVecEmpty()) { - if (cgFunc.GetLastBB()->GetPrev()->GetFirstStmt() == cgFunc.GetCleanupLabel() && - cgFunc.GetLastBB()->GetPrev()->GetPrev()) { - cgFunc.PushBackExitBBsVec(*cgFunc.GetLastBB()->GetPrev()->GetPrev()); - } else { + if (cgFunc.GetCleanupBB() != nullptr && cgFunc.GetCleanupBB()->GetPrev() != nullptr) { + cgFunc.PushBackExitBBsVec(*cgFunc.GetCleanupBB()->GetPrev()); + } else if (!cgFunc.GetMirModule().IsCModule()) { cgFunc.PushBackExitBBsVec(*cgFunc.GetLastBB()->GetPrev()); } } + cgFunc.SetHasProEpilogue(NeedProEpilog()); - if (proLog != nullptr) { - GenerateProlog(*proLog); - proLog->SetFastPath(true); - cgFunc.GetFirstBB()->SetFastPath(true); - } else { - GenerateProlog(*(cgFunc.GetFirstBB())); - } - + // not run proepilog analysis or analysis failed, insert proepilog at firstBB and exitBB + GenerateProlog(*(cgFunc.GetFirstBB())); for (auto *exitBB : cgFunc.GetExitBBsVec()) { - if (GetFastPathReturnBB() != exitBB) { - GenerateEpilog(*exitBB); - } + GenerateEpilog(*exitBB); } - if (cgFunc.GetFunction().IsJava()) { GenerateEpilogForCleanup(*(cgFunc.GetCleanupBB())); } - if (cgFunc.GetMirModule().IsCModule() && !exitBB2CallSitesMap.empty()) { - cgFunc.GetTheCFG()->InitInsnVisitor(cgFunc); - for (auto pair : exitBB2CallSitesMap) { - BB *curExitBB = pair.first; - MapleSet &callInsnsMap = pair.second; - SetCurTailcallExitBB(curExitBB); - ConvertToTailCalls(callInsnsMap); + // insert ret insn for exitBB + for (auto *exitBB : cgFunc.GetExitBBsVec()) { + if (cgFunc.GetHasProEpilogue() || (!exitBB->GetPreds().empty() && !TestPredsOfRetBB(*exitBB))) { + GenerateRet(*exitBB); } } } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reaching.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reaching.cpp index 1231b8ab59d858ba6f99e642af248243d8a92118..612ea239201f090c21512b4fd01d8dcae7a21537 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reaching.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reaching.cpp @@ -32,7 +32,7 @@ void AArch64ReachingDefinition::InitStartGen() CCLocInfo pLoc; for (uint32 i = 0; i < cgFunc->GetFunction().GetFormalCount(); ++i) { MIRType *type = cgFunc->GetFunction().GetNthParamType(i); - (void)parmLocator.LocateNextParm(*type, pLoc, i == 0, &cgFunc->GetFunction()); + (void)parmLocator.LocateNextParm(*type, pLoc, i == 0, cgFunc->GetFunction().GetMIRFuncType()); if (pLoc.reg0 == 0) { /* If is a large frame, parameter addressing mode is based vreg:Vra. */ continue; @@ -325,7 +325,8 @@ void AArch64ReachingDefinition::FindRegDefInBB(uint32 regNO, BB &bb, InsnSet &de return; } - FOR_BB_INSNS(insn, (&bb)) { + FOR_BB_INSNS(insn, (&bb)) + { if (!insn->IsMachineInstruction()) { continue; } @@ -438,7 +439,8 @@ void AArch64ReachingDefinition::FindMemDefInBB(uint32 offset, BB &bb, InsnSet &d return; } - FOR_BB_INSNS(insn, (&bb)) { + FOR_BB_INSNS(insn, (&bb)) + { if (!insn->IsMachineInstruction()) { continue; } @@ -601,7 +603,8 @@ InsnSet AArch64ReachingDefinition::FindDefForRegOpnd(Insn &insn, uint32 indexOrR if (insn.GetBB()->IsCleanup()) { DFSFindDefForRegOpnd(*insn.GetBB(), regNO, visitedBB, defInsnSet); if (defInsnSet.empty()) { - FOR_ALL_BB(bb, cgFunc) { + FOR_ALL_BB(bb, cgFunc) + { if (bb->IsCleanup()) { continue; } @@ -1030,7 +1033,8 @@ InsnSet AArch64ReachingDefinition::FindDefForMemOpnd(Insn &insn, uint32 indexOrO if (insn.GetBB()->IsCleanup()) { DFSFindDefForMemOpnd(*insn.GetBB(), memOffSet, visitedBB, defInsnSet); if (defInsnSet.empty()) { - FOR_ALL_BB(bb, cgFunc) { + FOR_ALL_BB(bb, cgFunc) + { if (bb->IsCleanup()) { continue; } @@ -1113,7 +1117,8 @@ void AArch64ReachingDefinition::InitGenUse(BB &bb, bool firstTime) return; } - FOR_BB_INSNS(insn, (&bb)) { + FOR_BB_INSNS(insn, (&bb)) + { if (!insn->IsMachineInstruction()) { continue; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cfi.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cfi.cpp index e76fe19ef0d63159f6bce0a6af3ca2a1c8a59184..00e0c01f134ffe830aa360a340aa77cee803ad36 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cfi.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cfi.cpp @@ -52,19 +52,18 @@ void CfiInsn::Dump() const LogInfo::MapleLogger() << "\n"; } -#if DEBUG -void CfiInsn::Check() const +bool CfiInsn::CheckMD() const { CfiDescr &cfiDescr = cfiDescrTable[GetMachineOpcode()]; /* cfi instruction's 3rd /4th/5th operand must be null */ for (uint32 i = 0; i < static_cast(cfiDescr.opndCount); ++i) { Operand &opnd = GetOperand(i); if (opnd.GetKind() != cfiDescr.opndTypes[i]) { - CHECK_FATAL(false, "incorrect operand in cfi insn"); + return false; } } + return true; } -#endif void RegOperand::Dump() const { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp index 6bd6e05f4c0f1c1cde9f97abcfa334f4f5868e3c..59e50eaacda1416ae388290382284c578ec4a57e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_option.cpp @@ -122,6 +122,7 @@ bool CGOptions::doCondBrAlign = false; bool CGOptions::cgBigEndian = false; bool CGOptions::arm64ilp32 = false; bool CGOptions::noCommon = false; +bool CGOptions::doCgirVerify = false; CGOptions &CGOptions::GetInstance() { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_options.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_options.cpp index 75082267384e1cd45062e4dbc6d02418a562caa5..97330fe14801f524504abac660f2b0eab7eefef6 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_options.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg_options.cpp @@ -538,5 +538,4 @@ maplecl::Option jumpAlignPow( maplecl::Option funcAlignPow( {"--func-align-pow"}, " --func-align-pow=NUM \tO2 func bb align pow (NUM == 0, no func-align)\n", {cgCategory}); - } // namespace opts::cg diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cgfunc.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cgfunc.cpp index d765a09ba3eebea3637631e71c3fe82ed66c02bc..239e05d0df4eaf05e65f22f2aac99ce255877353 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cgfunc.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cgfunc.cpp @@ -30,6 +30,70 @@ namespace maplebe { using namespace maple; #define JAVALANG (GetMirModule().IsJavaModule()) +// deal mem read/write node base info +void MemRWNodeHelper::GetMemRWNodeBaseInfo(const BaseNode &node, MIRFunction &mirFunc) +{ + if (node.GetOpCode() == maple::OP_iread) { + auto &iread = static_cast(node); + fieldId = iread.GetFieldID(); + auto *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread.GetTyIdx()); + DEBUG_ASSERT(type->IsMIRPtrType(), "expect a pointer type at iread node"); + auto *pointerType = static_cast(type); + mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx()); + if (mirType->GetKind() == kTypeArray) { + auto *arrayType = static_cast(mirType); + mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(arrayType->GetElemTyIdx()); + } + } else if (node.GetOpCode() == maple::OP_dassign) { + auto &dassign = static_cast(node); + fieldId = dassign.GetFieldID(); + symbol = mirFunc.GetLocalOrGlobalSymbol(dassign.GetStIdx()); + CHECK_FATAL(symbol != nullptr, "symbol should not be nullptr"); + mirType = symbol->GetType(); + } else if (node.GetOpCode() == maple::OP_dread) { + auto &dread = static_cast(node); + fieldId = dread.GetFieldID(); + symbol = mirFunc.GetLocalOrGlobalSymbol(dread.GetStIdx()); + CHECK_FATAL(symbol != nullptr, "symbol should not be nullptr"); + mirType = symbol->GetType(); + } else { + CHECK_FATAL(node.GetOpCode() == maple::OP_iassign, "unsupported OpCode"); + auto &iassign = static_cast(node); + fieldId = iassign.GetFieldID(); + auto &addrofNode = static_cast(iassign.GetAddrExprBase()); + auto *iassignMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iassign.GetTyIdx()); + MIRPtrType *pointerType = nullptr; + if (iassignMirType->GetPrimType() == PTY_agg) { + auto *addrSym = mirFunc.GetLocalOrGlobalSymbol(addrofNode.GetStIdx()); + auto *addrMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(addrSym->GetTyIdx()); + addrMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(addrMirType->GetTypeIndex()); + DEBUG_ASSERT(addrMirType->GetKind() == kTypePointer, "non-pointer"); + pointerType = static_cast(addrMirType); + } else { + DEBUG_ASSERT(iassignMirType->GetKind() == kTypePointer, "non-pointer"); + pointerType = static_cast(iassignMirType); + } + mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx()); + } +} + +void MemRWNodeHelper::GetTrueMirInfo(const BECommon &beCommon) +{ + // fixup mirType, primType and offset + if (fieldId != 0) { // get true field type + DEBUG_ASSERT((mirType->IsMIRStructType() || mirType->IsMIRUnionType() || mirType->IsMIRClassType()), + "non-structure"); + auto *structType = static_cast(mirType); + mirType = structType->GetFieldType(fieldId); + byteOffset = mirType->IsMIRClassType() + ? static_cast(beCommon.GetJClassFieldOffset(*structType, fieldId).byteOffset) + : static_cast(structType->GetFieldOffsetFromBaseAddr(fieldId).byteOffset); + isRefField = beCommon.IsRefField(*structType, fieldId); + } + primType = mirType->GetPrimType(); + // get mem size + memSize = static_cast(mirType->GetSize()); +} Operand *HandleDread(const BaseNode &parent, BaseNode &expr, CGFunc &cgFunc) { @@ -41,9 +105,6 @@ Operand *HandleRegread(const BaseNode &parent, BaseNode &expr, CGFunc &cgFunc) { (void)parent; auto ®ReadNode = static_cast(expr); - if (regReadNode.GetRegIdx() == -kSregRetval0 || regReadNode.GetRegIdx() == -kSregRetval1) { - return &cgFunc.ProcessReturnReg(regReadNode.GetPrimType(), -(regReadNode.GetRegIdx())); - } return cgFunc.SelectRegread(regReadNode); } @@ -2448,12 +2509,13 @@ void CGFunc::VerifyAllInsn() { FOR_BB_INSNS(insn, bb) { - if (!VERIFY_INSN(insn)) { - LogInfo::MapleLogger() << "Illegal insn is:\n"; - insn->Dump(); - LogInfo::MapleLogger() << "Function name is:\n" << GetName() << "\n"; - CHECK_FATAL_FALSE("The problem is illegal insn, info is above."); + if (VERIFY_INSN(insn) && insn->CheckMD()) { + continue; } + LogInfo::MapleLogger() << "Illegal insn is:\n"; + insn->Dump(); + LogInfo::MapleLogger() << "Function name is:\n" << GetName() << "\n"; + CHECK_FATAL_FALSE("The problem is illegal insn, info is above."); } } } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/dbg.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/dbg.cpp index e2fa441e43e8cc2626e89f80998b80b0f1582b7e..adc07a6a36880e089ba5166d2eef82e2d0c0a353 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/dbg.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/dbg.cpp @@ -49,19 +49,18 @@ void DbgInsn::Dump() const LogInfo::MapleLogger() << "\n"; } -#if DEBUG -void DbgInsn::Check() const +bool DbgInsn::CheckMD() const { DbgDescr &dbgDescr = dbgDescrTable[GetMachineOpcode()]; /* dbg instruction's 3rd /4th/5th operand must be null */ for (uint32 i = 0; i < dbgDescr.opndCount; ++i) { Operand &opnd = GetOperand(i); if (opnd.GetKind() != dbgDescr.opndTypes[i]) { - CHECK_FATAL(false, "incorrect operand in debug insn"); + return false; } } + return true; } -#endif uint32 DbgInsn::GetLoc() const { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/insn.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/insn.cpp index f6e1466420b2873cfb7a030d92b231a5a81c5ca8..a2e1ac0f7d9b79d18c3e51ae1f9812beee200d6d 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/insn.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/insn.cpp @@ -269,30 +269,30 @@ std::set Insn::GetDefRegs() const return defRegNOs; } -#if DEBUG -void Insn::Check() const +bool Insn::CheckMD() const { if (!md) { - CHECK_FATAL(false, " need machine description for target insn "); + LogInfo::MapleLogger() << " need machine description for target insn\n"; + return false; } /* check if the number of operand(s) matches */ uint32 insnOperandSize = GetOperandSize(); if (insnOperandSize != md->GetOpndMDLength()) { - CHECK_FATAL(false, " the number of operands in instruction does not match machine description "); + LogInfo::MapleLogger() << " need machine description for target insn\n"; + return false; } /* check if the type of each operand matches */ for (uint32 i = 0; i < insnOperandSize; ++i) { Operand &opnd = GetOperand(i); auto *opndDesc = md->GetOpndDes(i); if (opnd.IsImmediate()) { - CHECK_FATAL(opndDesc->IsImm(), "operand type does not match machine description!"); + return opndDesc->IsImm(); } else { - CHECK_FATAL(opnd.GetKind() == opndDesc->GetOperandType(), - "operand type does not match machine description!"); + return (opnd.GetKind() == opndDesc->GetOperandType()); } } + return true; } -#endif Insn *Insn::Clone(MemPool &memPool) const { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp index f713f331e4033e027e702d64f3b08e643be7423c..30e17a6d6a0904a6a6af82723b45be7284baa929 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/loop.cpp @@ -564,7 +564,7 @@ void LoopFinder::DetectInnerLoop() for (LoopHierarchy *loopHierarchy2 = loopHierarchy1->GetNext(); loopHierarchy2 != nullptr; loopHierarchy2 = loopHierarchy2->GetNext()) { if (loopHierarchy1->GetHeader() != loopHierarchy2->GetHeader()) { - auto &loopHierarchy2Members = loopHierarchy2->GetLoopMembers(); + const auto &loopHierarchy2Members = loopHierarchy2->GetLoopMembers(); if (find(loopHierarchy2Members.begin(), loopHierarchy2Members.end(), loopHierarchy1->GetHeader()) != loopHierarchy2Members.end()) { bool allin = true; @@ -605,7 +605,7 @@ static void CopyLoopInfo(const LoopHierarchy *from, CGFuncLoops *to, CGFuncLoops } for (auto *bb : from->GetLoopMembers()) { to->AddLoopMembers(*bb); - bb->SetLoop(*to); + bb->SetLoop(to); } for (auto *bb : from->GetBackedge()) { to->AddBackedge(*bb); @@ -648,6 +648,7 @@ void LoopFinder::FormLoopHierarchy() FOR_ALL_BB(bb, cgFunc) { bb->SetLevel(0); + bb->SetLoop(nullptr); } bool changed; do { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/proepilog.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/proepilog.cpp index 3149d9e9b8fcdf16b39a43214adfd49d90d58745..fcd6d87942741e6820ae13520b4e6e11e054e5c6 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/proepilog.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/proepilog.cpp @@ -19,98 +19,18 @@ namespace maplebe { using namespace maple; - -Insn *GenProEpilog::InsertCFIDefCfaOffset(int32 &cfiOffset, Insn &insertAfter) -{ - if (!cgFunc.GenCfi()) { - return &insertAfter; - } - cfiOffset = AddtoOffsetFromCFA(cfiOffset); - Insn &cfiInsn = cgFunc.GetInsnBuilder() - ->BuildCfiInsn(cfi::OP_CFI_def_cfa_offset) - .AddOpndChain(cgFunc.CreateCfiImmOperand(cfiOffset, k64BitSize)); - Insn *newIPoint = cgFunc.GetCurBB()->InsertInsnAfter(insertAfter, cfiInsn); - cgFunc.SetDbgCallFrameOffset(cfiOffset); - return newIPoint; -} - -/* there are two stack protector: - * 1. stack protector all: for all function - * 2. stack protector strong: for some functon that - * <1> invoke alloca functon; - * <2> use stack address; - * <3> callee use return stack slot; - * <4> local symbol is vector type; - * */ -void GenProEpilog::NeedStackProtect() -{ - DEBUG_ASSERT(stackProtect == false, "no stack protect default"); - CG *currCG = cgFunc.GetCG(); - if (currCG->IsStackProtectorAll()) { - stackProtect = true; - return; - } - - if (!currCG->IsStackProtectorStrong()) { - return; - } - - if (cgFunc.HasAlloca()) { - stackProtect = true; - return; - } - - /* check if function use stack address or callee function return stack slot */ - auto stackProtectInfo = cgFunc.GetStackProtectInfo(); - if ((stackProtectInfo & kAddrofStack) != 0 || (stackProtectInfo & kRetureStackSlot) != 0) { - stackProtect = true; - return; - } - - /* check if local symbol is vector type */ - auto &mirFunction = cgFunc.GetFunction(); - uint32 symTabSize = static_cast(mirFunction.GetSymTab()->GetSymbolTableSize()); - for (uint32 i = 0; i < symTabSize; ++i) { - MIRSymbol *symbol = mirFunction.GetSymTab()->GetSymbolFromStIdx(i); - if (symbol == nullptr || symbol->GetStorageClass() != kScAuto || symbol->IsDeleted()) { - continue; - } - TyIdx tyIdx = symbol->GetTyIdx(); - MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); - if (type->GetKind() == kTypeArray) { - stackProtect = true; - return; - } - - if (type->IsStructType() && IncludeArray(*type)) { - stackProtect = true; - return; - } - } -} - -bool GenProEpilog::IncludeArray(const MIRType &type) const -{ - DEBUG_ASSERT(type.IsStructType(), "agg must be one of class/struct/union"); - auto &structType = static_cast(type); - /* all elements of struct. */ - auto num = static_cast(structType.GetFieldsSize()); - for (uint32 i = 0; i < num; ++i) { - MIRType *elemType = structType.GetElemType(i); - if (elemType->GetKind() == kTypeArray) { - return true; - } - if (elemType->IsStructType() && IncludeArray(*elemType)) { - return true; - } - } - return false; -} - bool CgGenProEpiLog::PhaseRun(maplebe::CGFunc &f) { GenProEpilog *genPE = nullptr; - genPE = f.GetCG()->CreateGenProEpilog(f, *GetPhaseMemPool(), ApplyTempMemPool()); + if (Triple::GetTriple().IsAarch64BeOrLe()) { + genPE = f.GetCG()->CreateGenProEpilog(f, *GetPhaseMemPool(), ApplyTempMemPool()); + } +#if defined(TARGARM32) && TARGARM32 + genPE = GetPhaseAllocator()->New(f); +#endif + if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) { + genPE = f.GetCG()->CreateGenProEpilog(f, *GetPhaseMemPool()); + } genPE->Run(); return false; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp index 9d021e294e952f853f2ccb327da9415002ac9168..b7cf5ca5f71dcb23167324899f9b613f014b859b 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp @@ -1537,7 +1537,7 @@ void LSRALinearScanRegAllocator::SpillOperand(Insn &insn, Operand &opnd, bool is if (li->GetLastUse() == insn.GetId() && !cgFunc->IsRegReference(regNO)) { regInfo->FreeSpillRegMem(regNO); } - if (CGOptions::kVerboseCG) { + if (CGOptions::GetInstance().GenerateVerboseCG()) { std::string comment = " SPILL vreg:" + std::to_string(regNO); stInsn->SetComment(comment); } @@ -1563,7 +1563,7 @@ void LSRALinearScanRegAllocator::SpillOperand(Insn &insn, Operand &opnd, bool is if (li->GetLastUse() == insn.GetId() && !cgFunc->IsRegReference(regNO)) { regInfo->FreeSpillRegMem(regNO); } - if (CGOptions::kVerboseCG) { + if (CGOptions::GetInstance().GenerateVerboseCG()) { std::string comment = " RELOAD vreg" + std::to_string(regNO); ldInsn->SetComment(comment); } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_args.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_args.cpp index 2adc142f75257448a31f2322be1af385afc79e5c..ea1920ec065ba72d10399b68c69fb0e16f5523b8 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_args.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_args.cpp @@ -41,7 +41,7 @@ void X64MoveRegArgs::CollectRegisterArgs(std::map &argsList, std MIRFunction *func = const_cast(x64CGFunc->GetBecommon().GetMIRModule().CurFunction()); if (x64CGFunc->GetBecommon().HasFuncReturnType(*func)) { TyIdx tyIdx = x64CGFunc->GetBecommon().GetFuncReturnType(*func); - if (x64CGFunc->GetBecommon().GetTypeSize(tyIdx) <= k16ByteSize) { + if (GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx)->GetSize() <= k16ByteSize) { start = 1; } } @@ -72,15 +72,14 @@ void X64MoveRegArgs::CollectRegisterArgs(std::map &argsList, std } } -X64ArgInfo X64MoveRegArgs::GetArgInfo(std::map &argsList, - uint32 argIndex, std::vector &numFpRegs, - std::vector &fpSize) const +X64ArgInfo X64MoveRegArgs::GetArgInfo(std::map &argsList, uint32 argIndex, + std::vector &numFpRegs, std::vector &fpSize) const { X64CGFunc *x64CGFunc = static_cast(cgFunc); X64ArgInfo argInfo; argInfo.reg = argsList[argIndex]; argInfo.mirTy = x64CGFunc->GetFunction().GetNthParamType(argIndex); - argInfo.symSize = x64CGFunc->GetBecommon().GetTypeSize(argInfo.mirTy->GetTypeIndex()); + argInfo.symSize = argInfo.mirTy->GetSize(); argInfo.memPairSecondRegSize = 0; argInfo.doMemPairOpt = false; argInfo.createTwoStores = false; @@ -88,7 +87,7 @@ X64ArgInfo X64MoveRegArgs::GetArgInfo(std::map &argsList, if ((argInfo.symSize > k8ByteSize) && (argInfo.symSize <= k16ByteSize)) { argInfo.isTwoRegParm = true; if (numFpRegs[argIndex] > kOneRegister) { - argInfo.symSize = fpSize[argIndex]; + argInfo.symSize = argInfo.stkSize = fpSize[argIndex]; } else { if (argInfo.symSize > k12ByteSize) { argInfo.memPairSecondRegSize = k8ByteSize; @@ -97,12 +96,15 @@ X64ArgInfo X64MoveRegArgs::GetArgInfo(std::map &argsList, argInfo.memPairSecondRegSize = k4ByteSize; } argInfo.doMemPairOpt = true; - argInfo.symSize = GetPointerSize(); + argInfo.symSize = argInfo.stkSize = GetPointerSize(); } } else if (argInfo.symSize > k16ByteSize) { /* For large struct passing, a pointer to the copy is used. */ - argInfo.symSize = GetPointerSize(); + argInfo.symSize = argInfo.stkSize = GetPointerSize(); + } else if ((argInfo.mirTy->GetPrimType() == PTY_agg) && (argInfo.symSize < k8ByteSize)) { + argInfo.symSize = argInfo.stkSize = k8ByteSize; } else { + argInfo.stkSize = (argInfo.symSize < k4ByteSize) ? k4ByteSize : argInfo.symSize; if (argInfo.symSize > k4ByteSize) { argInfo.symSize = k8ByteSize; } else if ((argInfo.mirTy->GetPrimType() == PTY_agg) && (argInfo.symSize <= k4ByteSize)) { @@ -129,7 +131,7 @@ void X64MoveRegArgs::GenerateMovInsn(X64ArgInfo &argInfo, X64reg reg2) /* reg2 is required when the struct size is between 8-16 bytes */ X64CGFunc *x64CGFunc = static_cast(cgFunc); int32 stOffset = x64CGFunc->GetBaseOffset(*argInfo.symLoc); - RegOperand *baseOpnd = static_cast(x64CGFunc->GetBaseReg(*argInfo.symLoc)); + RegOperand *baseOpnd = x64CGFunc->GetBaseReg(*argInfo.symLoc); uint32 opndSize = argInfo.symSize * kBitsPerByte; RegOperand ®Opnd = x64CGFunc->GetOpndBuilder()->CreatePReg(argInfo.reg, opndSize, argInfo.regType); MemOperand *memOpnd = &x64CGFunc->GetOpndBuilder()->CreateMem(*baseOpnd, stOffset, opndSize); @@ -194,17 +196,17 @@ void X64MoveRegArgs::LoadStackArgsToVReg(MIRSymbol &mirSym) RegType regType = cgFunc->GetRegTyFromPrimTy(stype); auto symLoc = static_cast(x64CGFunc->GetMemlayout()->GetSymAllocInfo(mirSym.GetStIndex())); int32 stOffset = x64CGFunc->GetBaseOffset(*symLoc); - RegOperand *baseOpnd = static_cast(x64CGFunc->GetBaseReg(*symLoc)); + RegOperand *baseOpnd = x64CGFunc->GetBaseReg(*symLoc); MemOperand &memOpnd = x64CGFunc->GetOpndBuilder()->CreateMem(*baseOpnd, stOffset, opndSize); PregIdx pregIdx = x64CGFunc->GetFunction().GetPregTab()->GetPregIdxFromPregno(mirSym.GetPreg()->GetPregNo()); RegOperand &dstRegOpnd = x64CGFunc->GetOpndBuilder()->CreateVReg( - x64CGFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx), opndSize, regType); + x64CGFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx), opndSize, cgFunc->GetRegTyFromPrimTy(stype)); MOperator mOp; if (opndSize == k64BitSize) { mOp = regType == kRegTyInt ? x64::MOP_movq_m_r : x64::MOP_movfd_m_r; } else if (opndSize == k32BitSize) { - mOp = regType == kRegTyInt ? x64::MOP_movl_m_r : x64::MOP_movfs_m_r; + mOp = regType == kRegTyInt ? x64::MOP_movl_m_r : x64::MOP_movfs_m_r; } else if (opndSize == k16BitSize) { mOp = regType == kRegTyInt ? x64::MOP_movw_m_r : x64::MOP_begin; } else if (opndSize == k8BitSize) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_cgfunc.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_cgfunc.cpp index 6bf42ec9f4b9ed8011fc51ed2913e68f8e87c9a7..371a7c6a563f3fc932e3e8ad341cc8a1f60877d5 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_cgfunc.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_cgfunc.cpp @@ -588,12 +588,6 @@ void X64CGFunc::GenerateYieldpoint(BB &bb) { CHECK_FATAL(false, "NIY"); } -Operand &X64CGFunc::ProcessReturnReg(PrimType primType, int32 sReg) -{ - CHECK_FATAL(false, "NIY"); - Operand *a; - return *a; -} Operand &X64CGFunc::GetOrCreateRflag() { CHECK_FATAL(false, "NIY"); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp index d8e6a2b17f178b962300eaa676e871a0b9b5543a..30bc1b0906b2f53a142db5042ce1612957160bf0 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp @@ -241,10 +241,6 @@ uint32 X64Emitter::TransferFuncName(Operand *opnd) void X64Emitter::EmitInsn(Insn &insn, uint32 funcUniqueId) { -#if DEBUG - insn.Check(); -#endif - MOperator mop = insn.GetMachineOpcode(); const InsnDesc &curMd = X64CG::kMd[mop]; uint32 opndNum = curMd.GetOpndMDLength(); /* Get operands Number */ diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_proepilog.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_proepilog.cpp index 9da7b326335a54f0f036c4eff4bccb76c72c363d..fdce483b5cb21f6bc280b26890c54cd4faadac83 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_proepilog.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_proepilog.cpp @@ -21,16 +21,6 @@ namespace maplebe { using namespace maple; -/* - * If a function without callee-saved register, and end with a function call, - * then transfer bl/blr to b/br. - * Return value: true if function do not need Prologue/Epilogue. false otherwise. - */ -bool X64GenProEpilog::TailCallOpt() -{ - return false; -} - bool X64GenProEpilog::NeedProEpilog() { return true; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/all_attributes.def b/ecmascript/compiler/codegen/maple/maple_ir/include/all_attributes.def index 9d07dcb3fddd6727ec2074d519b01c5d854ab466..a9375c31f7a7f6d9115a34b85311280536d05737 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/all_attributes.def +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/all_attributes.def @@ -14,111 +14,115 @@ */ /* all possible attribute names from typeattrs.def, funcattrs.def and fieldattrs.def */ - ATTR(const) - ATTR(final) - ATTR(generic) - ATTR(implicit) - ATTR(private) - ATTR(protected) - ATTR(public) - ATTR(static) - ATTR(synthetic) - ATTR(used) - ATTR(hiddenapiblack) - ATTR(hiddenapigrey) +ATTR(const) +ATTR(final) +ATTR(generic) +ATTR(implicit) +ATTR(private) +ATTR(protected) +ATTR(public) +ATTR(static) +ATTR(synthetic) +ATTR(used) +ATTR(hiddenapiblack) +ATTR(hiddenapigrey) #ifdef FUNC_ATTR - ATTR(bridge) - ATTR(constructor) - ATTR(critical_native) - ATTR(declared_synchronized) - ATTR(default) - ATTR(destructor) - ATTR(delete) - ATTR(fast_native) - ATTR(inline) - ATTR(always_inline) - ATTR(noinline) - ATTR(native) - ATTR(strict) - ATTR(varargs) - ATTR(virtual) - ATTR(nosideeffect) - ATTR(pure) - ATTR(noexcept) - ATTR(nodefargeffect) - ATTR(nodefeffect) - ATTR(noretglobal) - ATTR(nothrow_exception) - ATTR(noretarg) - ATTR(noprivate_defeffect) - ATTR(ipaseen) - ATTR(rclocalunowned) - ATTR(callersensitive) - ATTR(weakref) - ATTR(safed) - ATTR(unsafed) - ATTR(noreturn) +ATTR(bridge) +ATTR(constructor) +ATTR(critical_native) +ATTR(declared_synchronized) +ATTR(default) +ATTR(destructor) +ATTR(delete) +ATTR(fast_native) +ATTR(inline) +ATTR(always_inline) +ATTR(noinline) +ATTR(native) +ATTR(strict) +ATTR(varargs) +ATTR(virtual) +ATTR(nosideeffect) +ATTR(pure) +ATTR(noexcept) +ATTR(nodefargeffect) +ATTR(nodefeffect) +ATTR(noretglobal) +ATTR(nothrow_exception) +ATTR(noretarg) +ATTR(noprivate_defeffect) +ATTR(ipaseen) +ATTR(rclocalunowned) +ATTR(callersensitive) +ATTR(weakref) +ATTR(safed) +ATTR(unsafed) +ATTR(noreturn) #endif #if defined(FUNC_ATTR) || defined(TYPE_ATTR) - ATTR(abstract) - ATTR(extern) - ATTR(interface) - ATTR(local) - ATTR(optimized) - ATTR(synchronized) - ATTR(weak) +ATTR(abstract) +ATTR(extern) +ATTR(interface) +ATTR(local) +ATTR(optimized) +ATTR(synchronized) +ATTR(weak) #endif #if defined(TYPE_ATTR) || defined(FIELD_ATTR) #include "memory_order_attrs.def" - ATTR(enum) - ATTR(restrict) - ATTR(transient) - ATTR(volatile) - ATTR(rcunowned) - ATTR(rcweak) - ATTR(final_boundary_size) - ATTR(tls_static) - ATTR(tls_dynamic) +ATTR(enum) +ATTR(restrict) +ATTR(transient) +ATTR(volatile) +ATTR(rcunowned) +ATTR(rcweak) +ATTR(final_boundary_size) +ATTR(tls_static) +ATTR(tls_dynamic) +ATTR(packed) #endif #ifdef TYPE_ATTR - ATTR(annotation) - ATTR(readonly) - ATTR(verified) - ATTR(localrefvar) - ATTR(rcunownedthis) - ATTR(incomplete_array) - ATTR(may_alias) - ATTR(static_init_zero) +ATTR(annotation) +ATTR(readonly) +ATTR(verified) +ATTR(localrefvar) +ATTR(rcunownedthis) +ATTR(incomplete_array) +ATTR(may_alias) +ATTR(static_init_zero) +ATTR(typedef) #endif #ifdef FUNC_ATTR - ATTR(firstarg_return) - ATTR(called_once) +ATTR(firstarg_return) +ATTR(called_once) #endif #ifdef STMT_ATTR - ATTR(insaferegion) +ATTR(insaferegion) +ATTR(mayTailcall) #endif - ATTR(oneelem_simd) - ATTR(nonnull) - ATTR(section) - ATTR(asmattr) +ATTR(oneelem_simd) +ATTR(nonnull) +ATTR(section) +ATTR(asmattr) #if defined(FUNC_ATTR) && !defined(NOCONTENT_ATTR) - ATTR(alias) - ATTR(constructor_priority) - ATTR(destructor_priority) +ATTR(alias) +ATTR(constructor_priority) +ATTR(destructor_priority) #endif #if (defined(TYPE_ATTR) || defined(FIELD_ATTR)) && !defined(NOCONTENT_ATTR) - ATTR(pack) +ATTR(pack) +ATTR(aligned) #endif #ifdef FUNC_ATTR - ATTR(initialization) - ATTR(termination) +ATTR(initialization) +ATTR(termination) #endif #if (defined(FUNC_ATTR) || defined(STMT_ATTR)) - ATTR(ccall) - ATTR(webkitjscall) - ATTR(ghcall) +ATTR(ccall) +ATTR(webkitjscall) +ATTR(ghcall) #endif #if defined(FUNC_ATTR) && !defined(NOCONTENT_ATTR) - ATTR(frame_pointer) - ATTR(frame_reserved_slots) +ATTR(frame_pointer) +ATTR(frame_reserved_slots) #endif \ No newline at end of file diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_builder.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_builder.h index 6bf18dd73a3e621e8b865cd64376593e8fc35742..9cffd7e380bda6891b5bc6378edcd06f3ecda472 100755 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_builder.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_builder.h @@ -289,7 +289,7 @@ public: IcallNode *CreateStmtIcall(const MapleVector &args); IcallNode *CreateStmtIcallAssigned(const MapleVector &args, const MIRSymbol &ret); IcallNode *CreateStmtIcallAssigned(const MapleVector &args, PregIdx pregIdx); - IcallNode *CreateStmtIcallproto(const MapleVector &args); + IcallNode *CreateStmtIcallproto(const MapleVector &args, const TyIdx &prototypeIdx); IcallNode *CreateStmtIcallprotoAssigned(const MapleVector &args, const MIRSymbol &ret); // For Call, VirtualCall, SuperclassCall, InterfaceCall IntrinsiccallNode *CreateStmtIntrinsicCall(MIRIntrinsicID idx, const MapleVector &arguments, diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_function.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_function.h index cfb5e42f6e0c9d756ce6984598ad4315705d1a6f..748cb070658ad73cb60f3c574b3f9964bb46afd9 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_function.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_function.h @@ -65,6 +65,7 @@ public: class MeFunction; // circular dependency exists, no other choice class EAConnectionGraph; // circular dependency exists, no other choice +class MemReferenceTable; class MIRFunction { public: MIRFunction(MIRModule *mod, StIdx idx) : module(mod), symbolTableIdx(idx) @@ -1541,6 +1542,20 @@ public: return funcAttrs.GetFrameResverdSlot(); } + MemReferenceTable *GetMemReferenceTable() + { + return memReferenceTable; + } + + void DiscardMemReferenceTable() + { + memReferenceTable = nullptr; + } + + void CreateMemReferenceTable(); + + MemReferenceTable *GetOrCreateMemReferenceTable(); + private: MIRModule *module; // the module that owns this function PUIdx puIdx = 0; // the PU index of this function @@ -1645,6 +1660,7 @@ private: uint64 fileLinenoChksum = 0; uint64 cfgChksum = 0; GcovFuncInfo *funcProfData = nullptr; + MemReferenceTable *memReferenceTable = nullptr; void DumpFlavorLoweredThanMmpl() const; MIRFuncType *ReconstructFormals(const std::vector &symbols, bool clearOldArgs); }; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h old mode 100755 new mode 100644 index 0738eadd19f773105c4df719ed0e2b6129fe50c1..e68ba2ba089ab400a05f44e9d09c784aa3ce246f --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h @@ -1827,6 +1827,16 @@ public: this->stmtAttrs.AppendAttr(stmtAttr.GetTargetAttrFlag(STMTATTR_insaferegion)); } + void SetMayTailcall(bool flag = true) + { + stmtAttrs.SetAttr(STMTATTR_mayTailcall, flag); + } + + bool GetMayTailCall() const + { + return stmtAttrs.GetAttr(STMTATTR_mayTailcall); + } + const StmtAttrs &GetStmtAttrs() const { return stmtAttrs; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_preg.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_preg.h index b24c4bdb5e1bd2ced1b60274a164a2323a765c93..bf14f2fdfbd378ab5f2db3a1766be8062adb9cfe 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_preg.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_preg.h @@ -33,7 +33,9 @@ enum SpecialReg : signed int { kSregMethodhdl = 5, kSregRetval0 = 6, kSregRetval1 = 7, - kSregLast = 8, + kSregRetval2 = 8, + kSregRetval3 = 9, + kSregLast = 10, }; #if MIR_FEATURE_FULL class MIRPreg { diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_type.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_type.h index c3c788856d6505265a0c0063bf67a1bb08007f4c..b7006f18813cd1f20a17c33dbc91334d921a9111 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_type.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_type.h @@ -28,6 +28,7 @@ namespace maple { constexpr uint32 kTypeHashLength = 12289; // hash length for mirtype, ref: planetmath.org/goodhashtableprimes const std::string kRenameKeyWord = "_MNO"; // A static symbol name will be renamed as oriname_MNOxxx. +const uint8 kAlignBase = 0; // alignment base class FieldAttrs; // circular dependency exists, no other choice using TyIdxFieldAttrPair = std::pair; @@ -118,6 +119,11 @@ inline bool MustBeAddress(PrimType tp) return (tp == PTY_ptr || tp == PTY_ref || tp == PTY_a64 || tp == PTY_a32); } +inline bool IsInt128Ty(PrimType type) +{ + return type == PTY_u128 || type == PTY_i128; +} + inline bool IsPrimitivePureScalar(PrimitiveType primitiveType) { return primitiveType.IsInteger() && !primitiveType.IsAddress() && !primitiveType.IsDynamic() && @@ -331,6 +337,16 @@ public: attrFlag = flag; } + void SetTypeAlignValue(uint8 align) + { + attrTypeAlign = align; + } + + uint8 GetTypeAlignValue() const + { + return attrTypeAlign; + } + uint64 GetAttrFlag() const { return attrFlag; @@ -375,6 +391,31 @@ public: return res; } + void SetTypeAlign(uint32 x) + { + DEBUG_ASSERT((~(x - 1) & x) == x, "SetTypeAlign called with non-power-of-2"); + attrTypeAlign = 0; + while (x != kAlignBase) { + x >>= 1; + ++attrTypeAlign; + } + } + + uint32 GetTypeAlign() const + { + if (attrTypeAlign == 1) { // align(1) + return 1; + } + constexpr uint32 square = 2; + uint32 res = 1; + uint32 exp = attrTypeAlign; + while (exp > 1) { // calculate align(x) + --exp; + res *= square; + } + return res; + } + bool operator==(const TypeAttrs &tA) const { return attrFlag == tA.attrFlag && attrAlign == tA.attrAlign && attrBoundary == tA.attrBoundary; @@ -421,15 +462,37 @@ public: } bool IsPacked() const + { + return GetAttr(ATTR_packed); + } + + bool HasPack() const { return GetAttr(ATTR_pack); } + bool IsTypedef() const + { + return GetAttr(ATTR_typedef); + } + + void SetOriginType(MIRType *basicType) + { + originType = basicType; + } + + MIRType *GetOriginType() const + { + return originType; + } + private: uint64 attrFlag = 0; uint8 attrAlign = 0; // alignment in bytes is 2 to the power of attrAlign + uint8 attrTypeAlign = 0; // alignment in bytes is 2 to the power of attrTypeAlign uint32 attrPack = -1; // -1 means inactive AttrBoundary attrBoundary; // boundary attr for EnhanceC + MIRType *originType = nullptr; }; enum FieldAttrKind { @@ -532,6 +595,11 @@ public: return GetAttr(FLDATTR_pack); } + bool HasAligned() const + { + return GetAttr(FLDATTR_aligned) || GetAlign() != 1; + } + private: uint8 attrAlign = 0; // alignment in bytes is 2 to the power of attrAlign uint32 attrFlag = 0; @@ -553,9 +621,13 @@ public: StmtAttrs &operator=(const StmtAttrs &p) = default; ~StmtAttrs() = default; - void SetAttr(StmtAttrKind x) + void SetAttr(StmtAttrKind x, bool flag = true) { - attrFlag |= (1u << static_cast(x)); + if (flag) { + attrFlag |= (1u << static_cast(x)); + } else { + attrFlag &= ~(1u << static_cast(x)); + } } bool GetAttr(StmtAttrKind x) const @@ -811,6 +883,16 @@ struct OffsetType { class MIRStructType; // circular dependency exists, no other choice class MIRFuncType; +// if it is a bitfield, byteoffset gives the offset of the container for +// extracting the bitfield and bitoffset is with respect to the current byte +struct FieldInfo { + FieldInfo(uint32 byte, uint32 bit) : byteOffset(byte), bitOffset(bit) {} + FieldInfo(uint32 byte, uint32 bit, FieldPair &pair) : byteOffset(byte), bitOffset(bit), fieldPair(&pair) {} + uint32 byteOffset; + uint32 bitOffset; + FieldPair *fieldPair = nullptr; +}; + class MIRType { public: MIRType(MIRTypeKind kind, PrimType pType) : typeKind(kind), primType(pType) {} @@ -891,6 +973,11 @@ public: return GetPrimTypeSize(primType); } + virtual uint32 GetUnadjustedAlign() const + { + return GetPrimTypeSize(primType); + } + virtual bool HasVolatileField() const { return false; @@ -1216,7 +1303,7 @@ public: bool HasFields() const override; uint32 NumberOfFieldIDs() const override; MIRStructType *EmbeddedStructType() override; - size_t ElemNumber(); + size_t ElemNumber() const; private: TyIdx eTyIdx {0}; @@ -1626,7 +1713,10 @@ public: bool IsLocal() const; size_t GetSize() const override; + uint32 GetTypedefOriginalAlign() const; uint32 GetAlign() const override; + uint32 GetAlignAux(bool toGetOriginal) const; + uint32 GetUnadjustedAlign() const override; size_t GetHashIndex() const override { @@ -1758,8 +1848,27 @@ public: int64 GetBitOffsetFromBaseAddr(FieldID fieldID) override; + FieldInfo GetFieldOffsetFromBaseAddr(FieldID fieldID) const; + bool HasPadding() const; + bool HasZeroWidthBitField() const; + + void AddFieldLayout(const FieldInfo &info) + { + fieldLayout.emplace_back(info); + } + + std::vector &GetFieldLayout() + { + if (!layoutComputed) { + ComputeLayout(); + } + return fieldLayout; + } + + uint32 GetFieldTypeAlignByFieldPair(const FieldPair &fieldPair); + protected: FieldVector fields {}; std::vector fieldInferredTyIdx {}; @@ -1781,14 +1890,19 @@ protected: std::vector inheritanceGeneric; TypeAttrs typeAttrs; mutable uint32 fieldsNum = kInvalidFieldNum; + mutable std::vector fieldLayout; mutable size_t size = kInvalidSize; + bool layoutComputed = false; + private: FieldPair TraverseToField(GStrIdx fieldStrIdx) const; bool HasVolatileFieldInFields(const FieldVector &fieldsOfStruct) const; bool HasTypeParamInFields(const FieldVector &fieldsOfStruct) const; int64 GetBitOffsetFromUnionBaseAddr(FieldID fieldID); int64 GetBitOffsetFromStructBaseAddr(FieldID fieldID); + void ComputeUnionLayout(); + void ComputeLayout(); }; // java array type, must not be nested inside another aggregate @@ -2532,6 +2646,10 @@ private: }; MIRType *GetElemType(const MIRType &arrayType); +// aarch64 specific +bool IsHomogeneousAggregates(const MIRType &ty, PrimType &primType, size_t &elemNum, bool firstDepth = true); +bool IsParamStructCopyToMemory(const MIRType &ty); +bool IsReturnInMemory(const MIRType &ty); #endif // MIR_FEATURE_FULL } // namespace maple diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp old mode 100755 new mode 100644 index 27377ae9d793e718335d2f13be17a7002bba98ab..f9c6462b432177e6dca0f1fec012ed12a9f414f1 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp @@ -297,8 +297,8 @@ MIRFunction *MIRBuilder::CreateFunction(const std::string &name, const MIRType & } } funcSymbol->SetTyIdx(GlobalTables::GetTypeTable() - .GetOrCreateFunctionType(returnType.GetTypeIndex(), funcVecType, funcVecAttrs, isVarg) - ->GetTypeIndex()); + .GetOrCreateFunctionType(returnType.GetTypeIndex(), funcVecType, funcVecAttrs, isVarg) + ->GetTypeIndex()); auto *funcType = static_cast(funcSymbol->GetType()); fn->SetMIRFuncType(funcType); funcSymbol->SetFunction(fn); @@ -843,7 +843,7 @@ ArrayNode *MIRBuilder::CreateExprArray(const MIRType &arrayType, BaseNode *op1, { ArrayNode *arrayNode = CreateExprArray(arrayType, op1); arrayNode->GetNopnd().push_back(op2); - arrayNode->SetNumOpnds(2); // 2 operands + arrayNode->SetNumOpnds(2); // 2 operands return arrayNode; } @@ -933,11 +933,12 @@ IcallNode *MIRBuilder::CreateStmtIcall(const MapleVector &args) return stmt; } -IcallNode *MIRBuilder::CreateStmtIcallproto(const MapleVector &args) +IcallNode *MIRBuilder::CreateStmtIcallproto(const MapleVector &args, const TyIdx &prototypeIdx) { auto *stmt = GetCurrentFuncCodeMp()->New(*GetCurrentFuncCodeMpAllocator(), OP_icallproto); DEBUG_ASSERT(stmt != nullptr, "stmt is null"); stmt->SetOpnds(args); + stmt->SetRetTyIdx(prototypeIdx); return stmt; } @@ -1198,7 +1199,7 @@ IfStmtNode *MIRBuilder::CreateStmtIfThenElse(BaseNode *cond) ifStmt->SetThenPart(thenBlock); auto *elseBlock = GetCurrentFuncCodeMp()->New(); ifStmt->SetElsePart(elseBlock); - ifStmt->SetNumOpnds(3); // 3 operands + ifStmt->SetNumOpnds(3); // 3 operands return ifStmt; } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp index 8ffaac1da58c5efb2fa078be740c056093377c1c..1544ccd97134d4c480409070b83427c171d95617 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp @@ -1424,25 +1424,94 @@ size_t MIRStructType::GetSize() const } uint32 MIRStructType::GetAlign() const +{ + return GetAlignAux(false); +} + +// return original align for typedef struct +uint32 MIRStructType::GetTypedefOriginalAlign() const +{ + return GetAlignAux(true); +} + +uint32 MIRStructType::GetAlignAux(bool toGetOriginal) const { if (fields.size() == 0) { - return 0; + return std::max(1u, GetTypeAttrs().GetAlign()); } uint32 maxAlign = 1; + uint32 maxZeroBitFieldAlign = 1; + auto structPack = GetTypeAttrs().GetPack(); + auto packed = GetTypeAttrs().IsPacked(); for (size_t i = 0; i < fields.size(); ++i) { TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i); MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first); - uint32 algn = fieldType->GetAlign(); - if (fieldType->GetKind() == kTypeBitField) { - algn = GetPrimTypeSize(fieldType->GetPrimType()); + auto originAlign = + fieldType->GetKind() != kTypeBitField ? fieldType->GetAlign() : GetPrimTypeSize(fieldType->GetPrimType()); + uint32 fieldAlign = + (packed || tfap.second.IsPacked()) ? static_cast(1U) : std::min(originAlign, structPack); + fieldAlign = tfap.second.HasAligned() ? std::max(fieldAlign, tfap.second.GetAlign()) : fieldAlign; + fieldAlign = GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign; + CHECK_FATAL(fieldAlign != 0, "expect fieldAlign not equal 0"); + maxAlign = std::max(maxAlign, fieldAlign); + if (fieldType->IsMIRBitFieldType() && static_cast(fieldType)->GetFieldSize() == 0) { + maxZeroBitFieldAlign = std::max(maxZeroBitFieldAlign, GetPrimTypeSize(fieldType->GetPrimType())); + } + } + uint32 attrAlign = GetTypeAttrs().GetAlign(); + if (GetTypeAttrs().IsTypedef()) { + // when calculating typedef's own size, we need to use its original align + if (toGetOriginal) { + // anonymous struct type def + if (GetTypeAttrs().GetOriginType() == nullptr) { + attrAlign = GetTypeAttrs().GetAlign(); + // unanonymous struct type def + } else { + attrAlign = static_cast(GetTypeAttrs().GetOriginType())->GetTypeAttrs().GetAlign(); + } + // when calculating typedef struct is a field of another struct, we need to use its typealign. } else { - algn = std::max(algn, tfap.second.GetAlign()); + attrAlign = GetTypeAttrs().GetTypeAlign(); } - if (maxAlign < algn) { - maxAlign = algn; + } + if (HasZeroWidthBitField()) { + return std::max(attrAlign, std::max(maxZeroBitFieldAlign, maxAlign)); + } + return std::max(attrAlign, maxAlign); +} + +// Used to determine date alignment in ABI. +// In fact, this alignment of type should be in the context of language/ABI, not MIRType. +// For simplicity, we implement it in MIRType now. +// Need check why "packed" is within the context of ABI. +uint32 MIRStructType::GetUnadjustedAlign() const +{ + if (fields.size() == 0) { + return 1u; + } + uint32 maxAlign = 1; + uint32 maxZeroBitFieldAlign = 1; + auto structPack = GetTypeAttrs().GetPack(); + auto packed = GetTypeAttrs().IsPacked(); + for (size_t i = 0; i < fields.size(); ++i) { + TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i); + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first); + auto originAlign = + fieldType->GetKind() != kTypeBitField ? fieldType->GetAlign() : GetPrimTypeSize(fieldType->GetPrimType()); + uint32 fieldAlign = + (packed || tfap.second.IsPacked()) ? static_cast(1U) : std::min(originAlign, structPack); + fieldAlign = tfap.second.HasAligned() ? std::max(fieldAlign, tfap.second.GetAlign()) : fieldAlign; + fieldAlign = GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign; + CHECK_FATAL(fieldAlign != 0, "expect fieldAlign not equal 0"); + maxAlign = std::max(maxAlign, fieldAlign); + if (fieldType->IsMIRBitFieldType() && static_cast(fieldType)->GetFieldSize() == 0) { + maxZeroBitFieldAlign = std::max(maxZeroBitFieldAlign, GetPrimTypeSize(fieldType->GetPrimType())); } } - return std::min(maxAlign, GetTypeAttrs().GetPack()); + if (HasZeroWidthBitField()) { + return std::max(maxZeroBitFieldAlign, maxAlign); + } + return maxAlign; } void MIRStructType::DumpFieldsAndMethods(int indent, bool hasMethod) const @@ -1734,7 +1803,7 @@ int64 MIRArrayType::GetBitOffsetFromArrayAddress(std::vector &indexArray) return offset; } -size_t MIRArrayType::ElemNumber() +size_t MIRArrayType::ElemNumber() const { size_t elemNum = 1; for (uint16 id = 0; id < dim; ++id) { @@ -2296,6 +2365,23 @@ int64 MIRStructType::GetBitOffsetFromBaseAddr(FieldID fieldID) return kOffsetUnknown; } +// compute the offset of the field given by fieldID within the structure type +// structy; it returns the answer in the pair (byteoffset, bitoffset) such that +// if it is a bitfield, byteoffset gives the offset of the container for +// extracting the bitfield and bitoffset is with respect to the current byte +FieldInfo MIRStructType::GetFieldOffsetFromBaseAddr(FieldID fieldID) const +{ + CHECK_FATAL(fieldID <= static_cast(NumberOfFieldIDs()), "GetBitOffsetFromBaseAddr: fieldID too large"); + if (GetKind() == kTypeClass || fieldID == 0) { + return {0, 0}; + } + if (GetKind() == kTypeUnion || GetKind() == kTypeStruct) { + return const_cast(this)->GetFieldLayout()[fieldID - 1]; + } + CHECK_FATAL(false, "Should never reach here!"); + return {0, 0}; +} + // Whether the memory layout of struct has paddings bool MIRStructType::HasPadding() const { @@ -2314,6 +2400,166 @@ bool MIRStructType::HasPadding() const return false; } +// On the ARM platform, when using both zero-sized bitfields and the pack attribute simultaneously, +// the size of a struct should be calculated according to the default alignment without the pack attribute. +bool MIRStructType::HasZeroWidthBitField() const +{ +#ifndef TARGAARCH64 + return false; +#endif + for (FieldPair field : fields) { + TyIdx fieldTyIdx = field.second.first; + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + if (fieldType->GetKind() == kTypeBitField && fieldType->GetSize() == 0) { + return true; + } + } + return false; +} + +uint32 MIRStructType::GetFieldTypeAlignByFieldPair(const FieldPair &fieldPair) +{ + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + auto fieldAttr = fieldPair.second.second; + auto fieldTypeAlign = + fieldType->GetKind() == kTypeBitField ? GetPrimTypeSize(fieldType->GetPrimType()) : fieldType->GetAlign(); + auto fieldPacked = GetTypeAttrs().IsPacked() || fieldAttr.IsPacked(); + auto fieldAlign = fieldPacked ? 1u : fieldTypeAlign; + fieldAlign = fieldAttr.HasAligned() ? std::max(fieldAlign, fieldAttr.GetAlign()) : fieldAlign; + return GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign; +} + +void MIRStructType::ComputeUnionLayout() +{ + size = 0; + for (FieldPair &field : fields) { + TyIdx fieldTyIdx = field.second.first; + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + MIRStructType *subStructType = fieldType->EmbeddedStructType(); + size = std::max(fieldType->GetSize(), size); + AddFieldLayout({0, 0, field}); + if (subStructType != nullptr) { + // if target field id is in the embedded structure, we should go into it by recursively call + // otherwise, just add the field-id number of the embedded structure, and continue to next field + auto &subStructFieldLayout = subStructType->GetFieldLayout(); + (void)fieldLayout.insert(fieldLayout.end(), subStructFieldLayout.begin(), subStructFieldLayout.end()); + } + } + if (GetTypeAttrs().IsTypedef()) { + size = RoundUp(size, GetTypedefOriginalAlign()); + } else { + size = RoundUp(size, GetAlign()); + } + CHECK_FATAL(fieldLayout.size() == NumberOfFieldIDs(), "fields layout != fieldID size"); + layoutComputed = true; +} + +void MIRStructType::ComputeLayout() +{ + if (layoutComputed) { + return; + } + if (GetKind() == kTypeUnion) { + ComputeUnionLayout(); + return; + } + uint32 allocedSize = 0; // space need for all fields before currentField + uint32 allocedBitSize = 0; + auto hasPack = GetTypeAttrs().HasPack(); + auto packed = GetTypeAttrs().IsPacked(); + constexpr uint8 bitsPerByte = 8; // 8 bits per byte + for (FieldPair &fieldPair : fields) { + auto tyIdxFieldAttrPair = fieldPair.second; + TyIdx fieldTyIdx = tyIdxFieldAttrPair.first; + auto fieldAttr = tyIdxFieldAttrPair.second; + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + auto fieldPacked = packed || fieldAttr.IsPacked(); + uint32 fieldAlign = GetFieldTypeAlignByFieldPair(fieldPair); + uint32 fieldAlignBits = fieldAlign * bitsPerByte; + uint32 fieldBitSize; + uint32 fieldTypeSize = static_cast(fieldType->GetSize()); + uint32 fieldTypeSizeBits = fieldTypeSize * bitsPerByte; + // case 1 : bitfield (including zero-width bitfield); + if (fieldType->GetKind() == kTypeBitField) { + fieldBitSize = static_cast(fieldType)->GetFieldSize(); + fieldTypeSizeBits = static_cast(GetPrimTypeSize(fieldType->GetPrimType())) * bitsPerByte; + // zero bit field + if (fieldAttr.HasAligned()) { + if ((fieldAttr.GetAlign() < fieldAlign && + fieldAttr.GetAlign() <= ((fieldTypeSizeBits - fieldBitSize) / bitsPerByte))) { + allocedBitSize = RoundUp(allocedBitSize, fieldAttr.GetAlign() * bitsPerByte); + } else { + allocedBitSize = RoundUp(allocedBitSize, fieldAlignBits); + } + } else if ((!hasPack && !fieldPacked && + ((allocedBitSize / fieldTypeSizeBits) != + ((allocedBitSize + fieldBitSize - 1u) / fieldTypeSizeBits))) || + fieldBitSize == 0) { + // the field is crossing the align boundary of its base type; + // align alloced_size_in_bits to fieldAlign + allocedBitSize = RoundUp(allocedBitSize, fieldTypeSizeBits); + } + auto info = + FieldInfo((allocedBitSize / fieldAlignBits) * fieldAlign, allocedBitSize % fieldAlignBits, fieldPair); + AddFieldLayout(info); + allocedBitSize += fieldBitSize; + fieldAlignBits = (fieldAlignBits) != 0 ? fieldAlignBits : fieldTypeSizeBits; + allocedSize = + std::max(allocedSize, static_cast(RoundUp(allocedBitSize, fieldAlignBits) / bitsPerByte)); + continue; + } // case 1 end + + bool leftOverBits = false; + uint32 offset = 0; + // no bit field before current field + if (allocedBitSize == allocedSize * bitsPerByte) { + allocedSize = RoundUp(allocedSize, fieldAlign); + offset = allocedSize; + } else { + // still some leftover bits on allocated words, we calculate things based on bits then. + if ((allocedBitSize / fieldAlignBits != (allocedBitSize + fieldTypeSizeBits - 1) / fieldAlignBits) || + fieldTypeSize == 0) { + // the field is crossing the align boundary of its base type + allocedBitSize = RoundUp(allocedBitSize, static_cast(fieldAlignBits)); + } + allocedSize = RoundUp(allocedSize, fieldAlign); + offset = (allocedBitSize / fieldAlignBits) * fieldAlign; + leftOverBits = true; + } + // target field id is found + MIRStructType *subStructType = fieldType->EmbeddedStructType(); + // case 2 : primitive field; + AddFieldLayout({offset, 0, fieldPair}); + if (subStructType != nullptr) { + // case 3 : normal (empty/non-empty) structure(struct/union) field; + // if target field id is in the embedded structure, we should go into it by recursively call + // otherwise, just add the field-id number of the embedded structure, and continue to next field + auto &subStructFieldOffsets = subStructType->GetFieldLayout(); + for (FieldInfo layout : subStructFieldOffsets) { + auto convertedLayout = layout; + convertedLayout.byteOffset += offset; + AddFieldLayout(convertedLayout); + } + } + if (leftOverBits) { + allocedBitSize += fieldTypeSizeBits; + allocedSize = + std::max(allocedSize, static_cast(RoundUp(allocedBitSize, fieldAlignBits) / bitsPerByte)); + } else if (!static_cast(fieldType)->IsIncompleteArray()) { + allocedSize += fieldTypeSize; + allocedBitSize = allocedSize * bitsPerByte; + } + } + if (GetTypeAttrs().IsTypedef()) { + allocedSize = RoundUp(allocedSize, GetTypedefOriginalAlign()); + } else { + allocedSize = RoundUp(allocedSize, GetAlign()); + } + size = allocedSize; + CHECK_FATAL(fieldLayout.size() == NumberOfFieldIDs(), "fields layout != fieldID size"); + layoutComputed = true; +} + // set hasVolatileField to true if parent type has volatile field, otherwise flase. static bool ParentTypeHasVolatileField(const TyIdx parentTyIdx, bool &hasVolatileField) { @@ -2552,5 +2798,159 @@ MIRType *GetElemType(const MIRType &arrayType) } return nullptr; } + +#ifdef TARGAARCH64 +static constexpr size_t kMaxHfaOrHvaElemNumber = 4; + +bool CheckHomogeneousAggregatesBaseType(PrimType type) +{ + if (type == PTY_f32 || type == PTY_f64 || type == PTY_f128 || IsPrimitiveVector(type)) { + return true; + } + return false; +} + +bool IsSameHomogeneousAggregatesBaseType(PrimType type, PrimType nextType) +{ + if ((type == PTY_f32 || type == PTY_f64 || type == PTY_f128) && type == nextType) { + return true; + } else if (IsPrimitiveVector(type) && IsPrimitiveVector(nextType) && + GetPrimTypeSize(type) == GetPrimTypeSize(nextType)) { + return true; + } + return false; +} + +bool IsUnionHomogeneousAggregates(const MIRStructType &ty, PrimType &primType, size_t &elemNum) +{ + primType = PTY_begin; + elemNum = 0; + for (const auto &field : ty.GetFields()) { + MIRType *filedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(field.second.first); + if (filedType->GetSize() == 0) { + continue; + } + PrimType filedPrimType = PTY_begin; + size_t filedElemNum = 0; + if (!IsHomogeneousAggregates(*filedType, filedPrimType, filedElemNum, false)) { + return false; + } + primType = (primType == PTY_begin) ? filedPrimType : primType; + if (!IsSameHomogeneousAggregatesBaseType(primType, filedPrimType)) { + return false; + } + elemNum = std::max(elemNum, filedElemNum); + } + return (ty.GetSize() == static_cast(GetPrimTypeSize(primType) * elemNum)); +} + +bool IsStructHomogeneousAggregates(const MIRStructType &ty, PrimType &primType, size_t &elemNum) +{ + primType = PTY_begin; + elemNum = 0; + FieldID fieldsNum = 0; + + for (const auto &field : ty.GetFields()) { + ++fieldsNum; + MIRType *filedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(field.second.first); + if (elemNum != 0 && primType != PTY_begin) { + uint32 curOffset = static_cast(GetPrimTypeSize(primType) * elemNum); + if (curOffset != ty.GetFieldOffsetFromBaseAddr(fieldsNum).byteOffset) { + return false; + } + } + fieldsNum += static_cast(filedType->NumberOfFieldIDs()); + if (filedType->GetSize() == 0) { + continue; + } + PrimType filedPrimType = PTY_begin; + size_t filedElemNum = 0; + if (!IsHomogeneousAggregates(*filedType, filedPrimType, filedElemNum, false)) { + return false; + } + elemNum += filedElemNum; + primType = (primType == PTY_begin) ? filedPrimType : primType; + if (elemNum > kMaxHfaOrHvaElemNumber || !IsSameHomogeneousAggregatesBaseType(primType, filedPrimType)) { + return false; + } + } + return (ty.GetSize() == static_cast(GetPrimTypeSize(primType) * elemNum)); +} + +bool IsArrayHomogeneousAggregates(const MIRArrayType &ty, PrimType &primType, size_t &elemNum) +{ + primType = PTY_begin; + elemNum = 0; + MIRType *elemMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ty.GetElemTyIdx()); + if (!IsHomogeneousAggregates(*elemMirType, primType, elemNum, false)) { + return false; + } + elemNum *= ty.ElemNumber(); + if (elemNum > kMaxHfaOrHvaElemNumber) { + return false; + } + uint32 needSize = static_cast(GetPrimTypeSize(primType) * elemNum); + return (ty.GetSize() == needSize); +} + +bool IsHomogeneousAggregates(const MIRType &ty, PrimType &primType, size_t &elemNum, bool firstDepth) +{ + if (firstDepth && ty.GetKind() == kTypeUnion) { + return IsUnionHomogeneousAggregates(static_cast(ty), primType, elemNum); + } + if (firstDepth && ty.GetKind() != kTypeStruct) { + return false; + } + primType = PTY_begin; + elemNum = 0; + if (ty.GetKind() == kTypeStruct) { + auto &structType = static_cast(ty); + return IsStructHomogeneousAggregates(structType, primType, elemNum); + } else if (ty.GetKind() == kTypeUnion) { + auto &unionType = static_cast(ty); + return IsUnionHomogeneousAggregates(unionType, primType, elemNum); + } else if (ty.GetKind() == kTypeArray) { + auto &arrType = static_cast(ty); + return IsArrayHomogeneousAggregates(arrType, primType, elemNum); + } else { + primType = ty.GetPrimType(); + elemNum = 1; + if (!CheckHomogeneousAggregatesBaseType(primType)) { + return false; + } + } + return (elemNum != 0); +} + +bool IsParamStructCopyToMemory(const MIRType &ty) +{ + if (ty.GetPrimType() == PTY_agg) { + PrimType primType = PTY_begin; + size_t elemNum = 0; + return !IsHomogeneousAggregates(ty, primType, elemNum) && ty.GetSize() > k16BitSize; + } + return false; +} + +bool IsReturnInMemory(const MIRType &ty) +{ + if (ty.GetPrimType() == PTY_agg) { + PrimType primType = PTY_begin; + size_t elemNum = 0; + return !IsHomogeneousAggregates(ty, primType, elemNum) && ty.GetSize() > k16BitSize; + } + return false; +} +#else +bool IsParamStructCopyToMemory(const MIRType &ty) +{ + return ty.GetPrimType() == PTY_agg && ty.GetSize() > k16BitSize; +} + +bool IsReturnInMemory(const MIRType &ty) +{ + return ty.GetPrimType() == PTY_agg && ty.GetSize() > k16BitSize; +} +#endif // TARGAARCH64 } // namespace maple #endif // MIR_FEATURE_FULL diff --git a/ecmascript/compiler/litecg_ir_builder.cpp b/ecmascript/compiler/litecg_ir_builder.cpp index 12d46f06826ab4a62b7f48cf149893a0ff94f050..fe1f0021439db11e5e9e3af1aaad1f8036485e3f 100644 --- a/ecmascript/compiler/litecg_ir_builder.cpp +++ b/ecmascript/compiler/litecg_ir_builder.cpp @@ -646,7 +646,7 @@ void LiteCGIRBuilder::VisitAdd(GateRef gate, GateRef e1, GateRef e2) result = lmirBuilder_->Add(returnType, tmp1Expr, tmp2Expr); } } else if (machineType == MachineType::F64) { - result = lmirBuilder_->Add(returnType, e1Value, e2Value); + result = lmirBuilder_->Add(lmirBuilder_->f64Type, e1Value, e2Value); } else { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE();