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 /* MapleIR headers. */ 29 #include "mir_nodes.h" 30 #include "mir_module.h" 31 #include "mir_function.h" 32 #include "mir_lower.h" 33 34 namespace maplebe { 35 class CGLowerer { 36 enum Option : uint64 { 37 kUndefined = 0, 38 kGenEh = 1ULL << 0, 39 kVerboseCG = 1ULL << 1, 40 }; 41 42 using BuiltinFunctionID = uint32; 43 using OptionFlag = uint64; 44 45 public: mirModule(mod)46 CGLowerer(MIRModule &mod, BECommon &common, MIRFunction *func = nullptr) : mirModule(mod), beCommon(common) 47 { 48 SetOptions(kGenEh); 49 mirBuilder = mod.GetMIRBuilder(); 50 SetCurrentFunc(func); 51 } 52 CGLowerer(MIRModule & mod,BECommon & common,bool genEh,bool verboseCG)53 CGLowerer(MIRModule &mod, BECommon &common, bool genEh, bool verboseCG) : mirModule(mod), beCommon(common) 54 { 55 OptionFlag option = 0; 56 if (genEh) { 57 option |= kGenEh; 58 } 59 if (verboseCG) { 60 option |= kVerboseCG; 61 } 62 SetOptions(option); 63 mirBuilder = mod.GetMIRBuilder(); 64 SetCurrentFunc(nullptr); 65 } 66 ~CGLowerer()67 ~CGLowerer() 68 { 69 mirBuilder = nullptr; 70 currentBlock = nullptr; 71 } 72 73 void LowerFunc(MIRFunction &func); 74 75 StmtNode *LowerDefaultIntrinsicCall(IntrinsiccallNode &intrinCall, MIRSymbol &st, MIRFunction &fn); 76 77 StmtNode *LowerIntrinsiccall(IntrinsiccallNode &intrinCall, BlockNode &); 78 GetCurrentFunc()79 MIRFunction *GetCurrentFunc() const 80 { 81 return mirModule.CurFunction(); 82 } 83 84 BaseNode *LowerExpr(BaseNode &, BaseNode &, BlockNode &); 85 86 BaseNode *LowerDread(DreadNode &dread, const BlockNode &block); 87 LowerIread(IreadNode & iread)88 BaseNode *LowerIread(IreadNode &iread) 89 { 90 /* use PTY_u8 for boolean type in dread/iread */ 91 if (iread.GetPrimType() == PTY_u1) { 92 iread.SetPrimType(PTY_u8); 93 } 94 CHECK_FATAL(iread.GetFieldID() == 0, "fieldID must be 0"); 95 return &iread; 96 } 97 98 BaseNode *LowerCastExpr(BaseNode &expr); 99 100 BaseNode *ExtractSymbolAddress(const StIdx &stIdx); 101 BaseNode *LowerDreadToThreadLocal(BaseNode &expr, const BlockNode &block); 102 StmtNode *LowerDassignToThreadLocal(StmtNode &stmt, const BlockNode &block); 103 104 void LowerDassign(DassignNode &dassign, BlockNode &block); 105 106 void LowerIassign(IassignNode &iassign, BlockNode &block); 107 108 void LowerRegassign(RegassignNode ®Assign, BlockNode &block); 109 LowerAddrof(AddrofNode & addrof)110 BaseNode *LowerAddrof(AddrofNode &addrof) const 111 { 112 return &addrof; 113 } 114 115 DassignNode *SaveReturnValueInLocal(StIdx, uint16); 116 BaseNode *NeedRetypeWhenLowerCallAssigned(PrimType pType); 117 void LowerCallStmt(StmtNode &, StmtNode *&, BlockNode &, MIRType *retty = nullptr, bool uselvar = false, 118 bool isIntrinAssign = false); 119 BlockNode *LowerIntrinsiccallAassignedToAssignStmt(IntrinsiccallNode &intrinsicCall); 120 BlockNode *LowerCallAssignedStmt(StmtNode &stmt, bool uselvar = false); 121 /* Intrinsiccall will processe return and vector as a call separately. 122 * To be able to handle them in a unified manner, we lower intrinsiccall to Intrinsicsicop. 123 */ 124 BlockNode *LowerIntrinsiccallToIntrinsicop(StmtNode &stmt); 125 126 void LowerStmt(StmtNode &stmt, BlockNode &block); 127 128 void LowerSwitchOpnd(StmtNode &stmt, BlockNode &block); 129 130 BlockNode *LowerBlock(BlockNode &block); 131 132 #if TARGARM32 || TARGAARCH64 || TARGRISCV64 || TARGX86_64 133 BlockNode *LowerReturnStructUsingFakeParm(NaryStmtNode &retNode); 134 #endif 135 BlockNode *LowerReturn(NaryStmtNode &retNode); 136 void LowerEntry(MIRFunction &func); 137 138 void CleanupBranches(MIRFunction &func) const; 139 140 void LowerTypePtr(BaseNode &expr) const; 141 142 /* A pseudo register refers to a symbol when DreadNode is converted to RegreadNode. */ GetSymbolReferredToByPseudoRegister(PregIdx regNO)143 StIdx GetSymbolReferredToByPseudoRegister(PregIdx regNO) const 144 { 145 (void)regNO; 146 return StIdx(); 147 } 148 SetOptions(OptionFlag option)149 void SetOptions(OptionFlag option) 150 { 151 options = option; 152 } 153 SetCheckLoadStore(bool value)154 void SetCheckLoadStore(bool value) 155 { 156 checkLoadStore = value; 157 } 158 159 /* if it defines a built-in to use for the given intrinsic, return the name. otherwise, return nullptr */ 160 PUIdx GetBuiltinToUse(BuiltinFunctionID id) const; 161 162 MIRModule &mirModule; 163 BECommon &beCommon; 164 BlockNode *currentBlock = nullptr; /* current block for lowered statements to be inserted to */ 165 bool checkLoadStore = false; 166 int64 seed = 0; 167 168 static constexpr PUIdx kFuncNotFound = PUIdx(-1); 169 static constexpr int kThreeDimArray = 3; 170 static constexpr int kNodeThirdOpnd = 2; 171 static constexpr int kMCCSyncEnterFast0 = 0; 172 static constexpr int kMCCSyncEnterFast1 = 1; 173 static constexpr int kMCCSyncEnterFast2 = 2; 174 static constexpr int kMCCSyncEnterFast3 = 3; 175 176 protected: 177 /* 178 * true if the lower level (e.g. mplcg) can handle the intrinsic directly. 179 * For example, the INTRN_MPL_ATOMIC_EXCHANGE_PTR can be directly handled by mplcg, 180 * and generate machine code sequences not containing any function calls. 181 * Such intrinsics will bypass the lowering of "assigned", 182 * and let mplcg handle the intrinsic results which are not return values. 183 */ 184 bool IsIntrinsicCallHandledAtLowerLevel(MIRIntrinsicID intrinsic) const; 185 186 private: SetCurrentFunc(MIRFunction * func)187 void SetCurrentFunc(MIRFunction *func) 188 { 189 mirModule.SetCurFunction(func); 190 } 191 ShouldAddAdditionalComment()192 bool ShouldAddAdditionalComment() const 193 { 194 return (options & kVerboseCG) != 0; 195 } 196 197 LabelIdx GetLabelIdx(MIRFunction &curFunc) const; 198 StmtNode *GenCallNode(const StmtNode &stmt, PUIdx &funcCalled, CallNode &origCall); 199 StmtNode *GenIntrinsiccallNode(const StmtNode &stmt, PUIdx &funcCalled, bool &handledAtLowerLevel, 200 IntrinsiccallNode &origCall); 201 StmtNode *GenIcallNode(PUIdx &funcCalled, IcallNode &origCall); 202 BlockNode *GenBlockNode(StmtNode &newCall, const CallReturnVector &p2nRets, const Opcode &opcode, 203 const PUIdx &funcCalled, bool handledAtLowerLevel, bool uselvar); 204 205 OptionFlag options = 0; 206 bool needBranchCleanup = false; 207 208 static std::vector<std::pair<BuiltinFunctionID, PUIdx>> builtinFuncIDs; 209 MIRBuilder *mirBuilder = nullptr; 210 uint32 labelIdx = 0; 211 }; 212 } /* namespace maplebe */ 213 214 #endif /* MAPLEBE_INCLUDE_BE_LOWERER_H */