• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &paramName);
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 &regAssign, 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