1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef MAPLEBE_INCLUDE_BE_LOWERER_H 17 #define MAPLEBE_INCLUDE_BE_LOWERER_H 18 /* C++ headers. */ 19 #include <vector> 20 #include <unordered_map> 21 #include <utility> 22 #include <cstddef> 23 #include <cstdarg> 24 #include <regex> 25 #include "intrinsics.h" /* For IntrinDesc. This includes 'intrinsic_op.h' as well */ 26 #include "becommon.h" 27 #include "cg.h" 28 #include "bbt.h" 29 /* MapleIR headers. */ 30 #include "mir_nodes.h" 31 #include "mir_module.h" 32 #include "mir_function.h" 33 #include "mir_lower.h" 34 #include "simplify.h" 35 36 namespace maplebe { 37 class CGLowerer { 38 enum Option : uint64 { 39 kUndefined = 0, 40 kGenEh = 1ULL << 0, 41 kVerboseCG = 1ULL << 1, 42 }; 43 44 using BuiltinFunctionID = uint32; 45 using OptionFlag = uint64; 46 47 public: mirModule(mod)48 CGLowerer(MIRModule &mod, BECommon &common, MIRFunction *func = nullptr) : mirModule(mod), beCommon(common) 49 { 50 SetOptions(kGenEh); 51 mirBuilder = mod.GetMIRBuilder(); 52 SetCurrentFunc(func); 53 } 54 CGLowerer(MIRModule & mod,BECommon & common,bool genEh,bool verboseCG)55 CGLowerer(MIRModule &mod, BECommon &common, bool genEh, bool verboseCG) : mirModule(mod), beCommon(common) 56 { 57 OptionFlag option = 0; 58 if (genEh) { 59 option |= kGenEh; 60 } 61 if (verboseCG) { 62 option |= kVerboseCG; 63 } 64 SetOptions(option); 65 mirBuilder = mod.GetMIRBuilder(); 66 SetCurrentFunc(nullptr); 67 } 68 ~CGLowerer()69 ~CGLowerer() 70 { 71 mirBuilder = nullptr; 72 currentBlock = nullptr; 73 } 74 75 MIRFunction *RegisterFunctionVoidStarToVoid(BuiltinFunctionID id, const std::string &name, 76 const std::string ¶mName); 77 78 void RegisterBuiltIns(); 79 80 void LowerFunc(MIRFunction &func); 81 82 BaseNode *LowerIntrinsicop(const BaseNode &, IntrinsicopNode &, BlockNode &); 83 84 BaseNode *LowerIntrinsicopwithtype(const BaseNode &, IntrinsicopNode &, BlockNode &); 85 86 StmtNode *LowerIntrinsicMplClearStack(const IntrinsiccallNode &intrinCall, BlockNode &newBlk); 87 88 StmtNode *LowerIntrinsicRCCall(const IntrinsiccallNode &intrinCall); 89 90 void LowerArrayStore(const IntrinsiccallNode &intrinCall, BlockNode &newBlk); 91 92 StmtNode *LowerDefaultIntrinsicCall(IntrinsiccallNode &intrinCall, MIRSymbol &st, MIRFunction &fn); 93 94 StmtNode *LowerIntrinsicMplCleanupLocalRefVarsSkip(IntrinsiccallNode &intrinCall); 95 96 StmtNode *LowerIntrinsiccall(IntrinsiccallNode &intrinCall, BlockNode &); 97 98 StmtNode *LowerSyncEnterSyncExit(StmtNode &stmt); 99 GetCurrentFunc()100 MIRFunction *GetCurrentFunc() const 101 { 102 return mirModule.CurFunction(); 103 } 104 105 BaseNode *LowerExpr(BaseNode &, BaseNode &, BlockNode &); 106 107 BaseNode *LowerDread(DreadNode &dread, const BlockNode &block); 108 LowerIread(IreadNode & iread)109 BaseNode *LowerIread(IreadNode &iread) 110 { 111 /* use PTY_u8 for boolean type in dread/iread */ 112 if (iread.GetPrimType() == PTY_u1) { 113 iread.SetPrimType(PTY_u8); 114 } 115 return (iread.GetFieldID() == 0 ? &iread : LowerIreadBitfield(iread)); 116 } 117 118 BaseNode *LowerCastExpr(BaseNode &expr); 119 120 BaseNode *ExtractSymbolAddress(const StIdx &stIdx); 121 BaseNode *LowerDreadToThreadLocal(BaseNode &expr, const BlockNode &block); 122 StmtNode *LowerDassignToThreadLocal(StmtNode &stmt, const BlockNode &block); 123 124 void LowerDassign(DassignNode &dassign, BlockNode &block); 125 126 void LowerResetStmt(StmtNode &stmt, BlockNode &block); 127 128 void LowerIassign(IassignNode &iassign, BlockNode &block); 129 130 void LowerRegassign(RegassignNode ®Assign, BlockNode &block); 131 132 void AddElemToPrintf(MapleVector<BaseNode *> &argsPrintf, int num, ...) const; 133 AssertBoundaryGetFileName(StmtNode & stmt)134 std::string AssertBoundaryGetFileName(StmtNode &stmt) 135 { 136 size_t pos = mirModule.GetFileNameFromFileNum(stmt.GetSrcPos().FileNum()).rfind('/'); 137 return mirModule.GetFileNameFromFileNum(stmt.GetSrcPos().FileNum()).substr(pos + 1); 138 } 139 140 std::string GetFileNameSymbolName(const std::string &fileName) const; 141 142 void SwitchAssertBoundary(StmtNode &stmt, MapleVector<BaseNode *> &argsPrintf); 143 144 void LowerAssertBoundary(StmtNode &stmt, BlockNode &block, BlockNode &newBlk, std::vector<StmtNode *> &abortNode); 145 146 StmtNode *LowerIntrinsicopDassign(const DassignNode &dassign, IntrinsicopNode &intrinsic, BlockNode &block); 147 148 void LowerGCMalloc(const BaseNode &node, const GCMallocNode &gcNode, BlockNode &blkNode, bool perm = false); 149 150 std::string GetNewArrayFuncName(const uint32 elemSize, const bool perm) const; 151 152 void LowerJarrayMalloc(const StmtNode &stmt, const JarrayMallocNode &node, BlockNode &block, bool perm = false); 153 LowerAddrof(AddrofNode & addrof)154 BaseNode *LowerAddrof(AddrofNode &addrof) const 155 { 156 return &addrof; 157 } 158 159 BaseNode *LowerIaddrof(const IreadNode &iaddrof); 160 BaseNode *SplitBinaryNodeOpnd1(BinaryNode &bNode, BlockNode &blkNode); 161 BaseNode *SplitTernaryNodeResult(TernaryNode &tNode, BaseNode &parent, BlockNode &blkNode); 162 bool IsComplexSelect(const TernaryNode &tNode) const; 163 int32 FindTheCurrentStmtFreq(const StmtNode *stmt) const; 164 BaseNode *LowerComplexSelect(const TernaryNode &tNode, BaseNode &parent, BlockNode &blkNode); 165 BaseNode *LowerFarray(ArrayNode &array); 166 BaseNode *LowerArrayDim(ArrayNode &array, int32 dim); 167 BaseNode *LowerArrayForLazyBiding(BaseNode &baseNode, BaseNode &offsetNode, const BaseNode &parent); 168 BaseNode *LowerArray(ArrayNode &array, const BaseNode &parent); 169 BaseNode *LowerCArray(ArrayNode &array); 170 171 DassignNode *SaveReturnValueInLocal(StIdx, uint16); 172 void LowerCallStmt(StmtNode &, StmtNode *&, BlockNode &, MIRType *retty = nullptr, bool uselvar = false, 173 bool isIntrinAssign = false); 174 BlockNode *LowerIntrinsiccallAassignedToAssignStmt(IntrinsiccallNode &intrinsicCall); 175 BlockNode *LowerCallAssignedStmt(StmtNode &stmt, bool uselvar = false); 176 bool LowerStructReturn(BlockNode &blk, StmtNode *stmt, StmtNode *&nextStmt, bool &lvar, BlockNode *oldblk); 177 BlockNode *LowerMemop(StmtNode &); 178 179 BaseNode *LowerRem(BaseNode &rem, BlockNode &block); 180 181 void LowerStmt(StmtNode &stmt, BlockNode &block); 182 183 void LowerSwitchOpnd(StmtNode &stmt, BlockNode &block); 184 185 MIRSymbol *CreateNewRetVar(const MIRType &ty, const std::string &prefix); 186 187 void RegisterExternalLibraryFunctions(); 188 189 BlockNode *LowerBlock(BlockNode &block); 190 191 void SimplifyBlock(BlockNode &block) const; 192 193 void LowerTryCatchBlocks(BlockNode &body); 194 195 #if TARGARM32 || TARGAARCH64 || TARGRISCV64 || TARGX86_64 196 BlockNode *LowerReturnStructUsingFakeParm(NaryStmtNode &retNode); 197 #endif 198 BlockNode *LowerReturn(NaryStmtNode &retNode); 199 void LowerEntry(MIRFunction &func); 200 201 StmtNode *LowerCall(CallNode &call, StmtNode *&stmt, BlockNode &block, MIRType *retty = nullptr, 202 bool uselvar = false); 203 void SplitCallArg(CallNode &callNode, BaseNode *newOpnd, size_t i, BlockNode &newBlk); 204 205 void CleanupBranches(MIRFunction &func) const; 206 207 void LowerTypePtr(BaseNode &expr) const; 208 209 BaseNode *GetBitField(int32 byteOffset, BaseNode *baseAddr, PrimType fieldPrimType); 210 StmtNode *WriteBitField(const std::pair<int32, int32> &byteBitOffsets, const MIRBitFieldType *fieldType, 211 BaseNode *baseAddr, BaseNode *rhs, BlockNode *block); 212 BaseNode *ReadBitField(const std::pair<int32, int32> &byteBitOffsets, const MIRBitFieldType *fieldType, 213 BaseNode *baseAddr); 214 BaseNode *LowerDreadBitfield(DreadNode &dread); 215 BaseNode *LowerIreadBitfield(IreadNode &iread); 216 StmtNode *LowerDassignBitfield(DassignNode &dassign, BlockNode &block); 217 StmtNode *LowerIassignBitfield(IassignNode &iassign, BlockNode &block); 218 219 void LowerAsmStmt(AsmNode *asmNode, BlockNode *blk); 220 ShouldOptarray()221 bool ShouldOptarray() const 222 { 223 DEBUG_ASSERT(mirModule.CurFunction() != nullptr, "nullptr check"); 224 return MIRLower::ShouldOptArrayMrt(*mirModule.CurFunction()); 225 } 226 227 BaseNode *NodeConvert(PrimType mtype, BaseNode &expr); 228 /* Lower pointer/reference types if found in pseudo registers. */ 229 void LowerPseudoRegs(const MIRFunction &func) const; 230 231 /* A pseudo register refers to a symbol when DreadNode is converted to RegreadNode. */ GetSymbolReferredToByPseudoRegister(PregIdx regNO)232 StIdx GetSymbolReferredToByPseudoRegister(PregIdx regNO) const 233 { 234 (void)regNO; 235 return StIdx(); 236 } 237 SetOptions(OptionFlag option)238 void SetOptions(OptionFlag option) 239 { 240 options = option; 241 } 242 SetCheckLoadStore(bool value)243 void SetCheckLoadStore(bool value) 244 { 245 checkLoadStore = value; 246 } 247 248 /* if it defines a built-in to use for the given intrinsic, return the name. otherwise, return nullptr */ 249 PUIdx GetBuiltinToUse(BuiltinFunctionID id) const; 250 void InitArrayClassCacheTableIndex(); 251 252 MIRModule &mirModule; 253 BECommon &beCommon; 254 BlockNode *currentBlock = nullptr; /* current block for lowered statements to be inserted to */ 255 bool checkLoadStore = false; 256 int64 seed = 0; 257 SimplifyMemOp simplifyMemOp; 258 static const std::string kIntrnRetValPrefix; 259 static const std::string kUserRetValPrefix; 260 261 static constexpr PUIdx kFuncNotFound = PUIdx(-1); 262 static constexpr int kThreeDimArray = 3; 263 static constexpr int kNodeThirdOpnd = 2; 264 static constexpr int kMCCSyncEnterFast0 = 0; 265 static constexpr int kMCCSyncEnterFast1 = 1; 266 static constexpr int kMCCSyncEnterFast2 = 2; 267 static constexpr int kMCCSyncEnterFast3 = 3; 268 269 protected: 270 /* 271 * true if the lower level (e.g. mplcg) can handle the intrinsic directly. 272 * For example, the INTRN_MPL_ATOMIC_EXCHANGE_PTR can be directly handled by mplcg, 273 * and generate machine code sequences not containing any function calls. 274 * Such intrinsics will bypass the lowering of "assigned", 275 * and let mplcg handle the intrinsic results which are not return values. 276 */ 277 bool IsIntrinsicCallHandledAtLowerLevel(MIRIntrinsicID intrinsic) const; 278 279 bool IsIntrinsicOpHandledAtLowerLevel(MIRIntrinsicID intrinsic) const; 280 281 private: SetCurrentFunc(MIRFunction * func)282 void SetCurrentFunc(MIRFunction *func) 283 { 284 mirModule.SetCurFunction(func); 285 simplifyMemOp.SetFunction(func); 286 if (func != nullptr) { 287 const std::string &dumpFunc = CGOptions::GetDumpFunc(); 288 const bool debug = CGOptions::GetDumpPhases().find("cglower") != CGOptions::GetDumpPhases().end() && 289 (dumpFunc == "*" || dumpFunc == func->GetName()); 290 simplifyMemOp.SetDebug(debug); 291 } 292 } 293 ShouldAddAdditionalComment()294 bool ShouldAddAdditionalComment() const 295 { 296 return (options & kVerboseCG) != 0; 297 } 298 GenerateExceptionHandlingCode()299 bool GenerateExceptionHandlingCode() const 300 { 301 return (options & kGenEh) != 0; 302 } 303 304 BaseNode *MergeToCvtType(PrimType dtyp, PrimType styp, BaseNode &src) const; 305 BaseNode *LowerJavascriptIntrinsicop(IntrinsicopNode &intrinNode, const IntrinDesc &desc); 306 StmtNode *CreateStmtCallWithReturnValue(const IntrinsicopNode &intrinNode, const MIRSymbol &ret, PUIdx bFunc, 307 BaseNode *extraInfo = nullptr) const; 308 StmtNode *CreateStmtCallWithReturnValue(const IntrinsicopNode &intrinNode, PregIdx retPregIdx, PUIdx bFunc, 309 BaseNode *extraInfo = nullptr) const; 310 BaseNode *LowerIntrinsicop(const BaseNode &parent, IntrinsicopNode &intrinNode); 311 BaseNode *LowerIntrinJavaMerge(const BaseNode &parent, IntrinsicopNode &intrinNode); 312 BaseNode *LowerIntrinJavaArrayLength(const BaseNode &parent, IntrinsicopNode &intrinNode); 313 BaseNode *LowerIntrinsicopWithType(const BaseNode &parent, IntrinsicopNode &intrinNode); 314 315 MIRType *GetArrayNodeType(BaseNode &baseNode); 316 IreadNode &GetLenNode(BaseNode &opnd0); 317 LabelIdx GetLabelIdx(MIRFunction &curFunc) const; 318 void ProcessArrayExpr(BaseNode &expr, BlockNode &blkNode); 319 void ProcessClassInfo(MIRType &classType, bool &classInfoFromRt, std::string &classInfo) const; 320 StmtNode *GenCallNode(const StmtNode &stmt, PUIdx &funcCalled, CallNode &origCall); 321 StmtNode *GenIntrinsiccallNode(const StmtNode &stmt, PUIdx &funcCalled, bool &handledAtLowerLevel, 322 IntrinsiccallNode &origCall); 323 StmtNode *GenIcallNode(PUIdx &funcCalled, IcallNode &origCall); 324 BlockNode *GenBlockNode(StmtNode &newCall, const CallReturnVector &p2nRets, const Opcode &opcode, 325 const PUIdx &funcCalled, bool handledAtLowerLevel, bool uselvar); 326 BaseNode *GetClassInfoExprFromRuntime(const std::string &classInfo); 327 BaseNode *GetClassInfoExprFromArrayClassCache(const std::string &classInfo); 328 BaseNode *GetClassInfoExpr(const std::string &classInfo) const; 329 BaseNode *GetBaseNodeFromCurFunc(MIRFunction &curFunc, bool isJarray); 330 331 OptionFlag options = 0; 332 bool needBranchCleanup = false; 333 bool hasTry = false; 334 335 static std::vector<std::pair<BuiltinFunctionID, PUIdx>> builtinFuncIDs; 336 MIRBuilder *mirBuilder = nullptr; 337 uint32 labelIdx = 0; 338 static std::unordered_map<IntrinDesc *, PUIdx> intrinFuncIDs; 339 static std::unordered_map<std::string, size_t> arrayClassCacheIndex; 340 }; 341 } /* namespace maplebe */ 342 343 #endif /* MAPLEBE_INCLUDE_BE_LOWERER_H */ 344