• 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 MAPLE_LITECG_LMIR_BUILDER_H
17 #define MAPLE_LITECG_LMIR_BUILDER_H
18 
19 #include <cstdint>
20 #include <variant>
21 #include <vector>
22 #include <map>
23 #include <string>
24 #include <utility>
25 #include <unordered_map>
26 #include "mpl_logging.h"
27 
28 /*
29   LMIR API exported.
30 
31   LMIR, the low-level MIR, will serve as the canonical input for LiteCG.
32 
33   Currently, it only contains the minimum set of features enough to
34   support eCompiler scenarioes. Later it will grow to be a complete core
35   set, but still with "just enough" features for general cases.
36 
37   Additional features, will be defined with x-extension strategy.
38 
39   The motivation of LMIR, is to hide the whole complexity of MIR interfaces,
40   and this should make integration of maple components easier.
41  */
42 namespace maple {
43 
44 /* import types for MIR: this is basically a simplification
45    we just need declaration, not headers.
46  */
47 class MIRBuilder;  // currently we just delegate MIRBuilder
48 class MIRModule;
49 class MIRFunction;
50 class MIRType;
51 class MIRFuncType;
52 class MIRConst;
53 class MIRAggConst;
54 class MIRSymbol;
55 class StmtNode;
56 class BaseNode;
57 class BlockNode;
58 class MIRPreg;
59 
60 namespace litecg {
61 
62 // Our type abstraction. currently delegate to MIR
63 
64 using String = std::string;
65 
66 using Module = MIRModule;
67 using Function = MIRFunction;
68 
69 // Note: Type is base class of all other Types
70 using Type = MIRType;              // base class of all Types
71 using Const = MIRConst;
72 using StructConst = MIRAggConst;
73 using ArrayConst = MIRAggConst;
74 using Var = MIRSymbol;
75 using Stmt = StmtNode;
76 using BB = BlockNode;  // A temporary faked BB
77 
78 using Param = std::pair<const String, Type *>;
79 using Params = std::vector<Param>;
80 using FieldOffset = std::pair<int32_t, int32_t>;  // (byteoffset, bitoffset)
81 using PregIdx = int32_t;
82 
83 // enumerations
84 enum class MIRIntrinsic {
85 #define DEF_MIR_INTRINSIC(STR, NAME, INTRN_CLASS, RETURN_TYPE, ...) INTRN_##STR,
86 #include "intrinsics.def"
87 #undef DEF_MIR_INTRINSIC
88 };
89 using IntrinsicId = MIRIntrinsic;
90 /* available intrinsic should be list here. like:
91    INTRN_memcpy, INTRN_memset, etc.
92  */
93 class Expr {
94 public:
Expr(BaseNode * baseNode,Type * nodeType)95     Expr(BaseNode *baseNode, Type *nodeType) : node(baseNode), type(nodeType) {}
96 
Expr()97     Expr() : node(nullptr), type(nullptr) {}
98 
99     ~Expr() = default;
100 
GetNode()101     BaseNode *GetNode()
102     {
103         return node;
104     }
105 
GetNode()106     BaseNode *GetNode() const
107     {
108         return node;
109     }
110 
GetType()111     Type *GetType()
112     {
113         return type;
114     }
115 
GetType()116     Type *GetType() const
117     {
118         return type;
119     }
120 
121     bool IsDread() const;
122     bool IsRegread() const;
123     bool IsConstValue() const;
124 
125 private:
126     BaseNode *node;
127     Type *type;
128 };
129 
130 enum LiteCGValueKind {
131     kPregKind,
132     kSymbolKind,
133     kConstKind,
134     kGlueAdd,
135     kPregPairKind,
136 };
137 
138 struct LiteCGValue {
139     LiteCGValueKind kind;
140     std::variant<PregIdx, MIRSymbol*, MIRConst*, std::pair<PregIdx, PregIdx>> data;
141 };
142 
143 using Args = std::vector<Expr>;
144 
145 enum FuncAttr {     // visibility of the defined function
146     FUNC_global,    // function has global visibility
147     FUNC_weak,      // weak function defined in this module
148     FUNC_internal,  // function defined and only used in this module
149 };
150 
151 enum GlobalRegister {
152     kSregSp = -1,
153     kSregFp = -2,
154 };
155 
156 enum ConvAttr {
157     CCall,
158     Web_Kit_JS_Call,
159     GHC_Call,
160 };
161 
162 enum GlobalVarAttr {
163     VAR_external,  // global variable declaration (no definition)
164     VAR_weak,      // weak function defined in this module
165     VAR_internal,  // variable defined and only used in this module
166     VAR_global,    // exported variable defined in this module
167     VAR_readonly,  // this is additional flag, default is R/W
168 };
169 
170 enum IntCmpCondition {
171     kEQ,
172     kNE,
173     kULT,
174     kULE,
175     kUGT,
176     kUGE,
177     kSLT,
178     kSLE,
179     kSGT,
180     kSGE,
181 };
182 
183 enum FloatCmpCondition {
184     kOLT,
185     kOLE,
186     kOGT,
187     kOGE,
188     kONE,
189     kOEQ,
190 };
191 
192 enum LiteCGTypeKind {
193     kLiteCGTypeUnknown,
194     kLiteCGTypeScalar,
195     kLiteCGTypeArray,
196     kLiteCGTypePointer,
197     kLiteCGTypeFunction,
198     kLiteCGTypeVoid,
199     kLiteCGTypeByName,
200 };
201 
202 // FieldAttr: do we need to support volatile here?
203 // using FieldAttr = AttrKind
204 /* used attribute for field:
205    ATTR_volatile
206  */
207 
208 using FieldId = uint32_t;
209 /* Use FieldId from MIR directly: it's a uint32_t, but with special meaning
210    for FieldId == 0: refer to the "whole" of the type
211    To avoid conflict with MIR type define, here using type name "FieldId"
212  */
213 
214 Module *CreateModuleWithName(const std::string &name);
215 void ReleaseModule(Module *module);
216 
217 /**
218  * a simplified, specialized MapleIR builder for LiteCG
219  * The basic IR set
220  *
221  * General rule for the interface:
222  *  + if function returns value type, then returns type is value type
223  *  + otherwise if the return value can be null, return type is pointer
224  *    caller should check for null
225  *  + otherwise the return type is reference.
226  *
227  *  + for compound IR (need to be constructed with a sequence of calls,
228  *      e.g., struct type/const, array const, function, switch), using
229  *    specific builder class to do the "chained" construction.
230  *
231  */
232 class LMIRBuilder {
233 public:
234     LMIRBuilder(Module &module);
235     ~LMIRBuilder() = default;
236 
237 #ifdef ARK_LITECG_DEBUG
238     void DumpIRToFile(const std::string fileName);
239 #endif
240 
241     LiteCGTypeKind LiteCGGetTypeKind(Type *type) const;
242     void SetCallStmtDeoptBundleInfo(Stmt &icallNode, const std::unordered_map<int, LiteCGValue> &deoptBundleInfo);
243 
244     // Type creation (currently all in global scope)
245     /*
246        For primitive types, using LMIRBuilder's public member:
247        i8Type, u8Type, etc.
248      */
249 
250     // derived type creation
251     Type *CreatePtrType(Type *mirType);
252     Type *CreateRefType(Type *mirType);
253 
254     bool IsHeapPointerType(Type *mirType) const;
255 
256     // for function pointer
257     Type *CreateFuncType(std::vector<Type *> params, Type *retType, bool isVarg);
258 
259     Type *LiteCGGetPointedType(Type *type);
260 
261     std::vector<Type *> LiteCGGetFuncParamTypes(Type *type);
262 
263     Type *LiteCGGetFuncReturnType(Type *type);
264     // still need interface for AddressOfFunction
265 
266     // Function declaration and definition
267     /* using FunctionBuilder interface for Function creation:
268          // i32 myfunc(i32 param1, i64 param2) { }
269          auto structType = DefineFunction("myfunc")
270                              .Param(i32Type, "param1")
271                              .Param(i64Type, "param2")
272                              .Ret(i32Type)               // optional for void
273                              .Done();
274 
275          auto structType = DeclareFunction("myfunc1")
276                              .Param(i32Type, "param1")
277                              .Param(i64Type, "param2")
278                              .Ret(i32Type)
279                              .Done();
280      */
281 
282     // This is to enable forwarded call before its definition
283     // can return null. caller should check for null.
284     Function *GetFunc(const String &name);  // get a function by its unique name
285 
286     // when a function is set as current function (of the module), local
287     // declarations and statements are insert into it.
288     void SetCurFunc(Function &function);
289 
290     Function &GetCurFunction() const;
291 
292     void RenameFormal2Preg(Function &func);
293 
294     Expr LiteCGGetPregFP(Function &func);
295     Expr LiteCGGetPregSP();
296 
297     Var &CreateLocalVar(Type *type, const String &name);
298     Var *GetLocalVar(const String &name);
299     Var *GetLocalVarFromExpr(Expr inExpr);
300     void SetFunctionDerived2BaseRef(PregIdx derived, PregIdx base);
301     PregIdx GetPregIdxFromExpr(const Expr &expr);
302     Var &GetParam(Function &function, size_t index) const;
303     Expr GenExprFromVar(Var &var);
304 
305     Const &CreateIntConst(Type *type, int64_t val);
306     Const &CreateDoubleConst(double val);
307     Const *GetConstFromExpr(const Expr &expr);
308 
309     /* using ArrayConstBuilder interface for ArrayConst creation:
310        Note: the elements should be added consequentially, and match the dim size.
311          auto arrayConst = CreateArrayConst(arrayType)
312                               .Element(CreateIntConst(i32Type, 0))
313                               .Element(CreateIntConst(i32Type, 0))
314                               .Done();
315        or using the following form:
316          auto arrayConst = CreateArrayConst(arrayType).Dim({0, 0}).Done();
317      */
318 
319     /*
320       BB is the container node for a sequence or linear statements,
321       if needLabel == true, implicitly create a label node as its first statement.
322       BB also servers as target for Gotos, when it's a goto target, it
323       should have needLabel == true
324      */
325     BB &CreateBB(bool needLabel = true);
326     void AppendStmt(BB &bb, Stmt &stmt);              // append stmt to the back of BB
327     void AppendStmtBeforeBranch(BB &bb, Stmt &stmt);  // append stmt after the first non-jump stmt in back of BB
328     void AppendBB(BB &bb);    // append BB to the back of current function;
329     void AppendToLast(BB &bb);
330     BB &GetLastPosBB();
331     BB &GetLastAppendedBB();  // get last appended BB of current function
332 
333     void SetStmtCallConv(Stmt &stmt, ConvAttr convAttr);
334 
335     // statements
336     Stmt &Goto(BB &dest);  // jump without condition
337     /* conditional goto:
338        when inverseCond == true, using (!cond) as condition
339 
340        1. if(cond)-then form code should be generated this way:
341 
342          if(!cond) goto BB_end    // CondGoto(cond, BB_end, true);
343          BB_ifTrue: {...}
344          BB_end: {...}
345 
346        2. if-then-else form code should be generated this way:
347          if(cond) goto BB_ifTrue  // CondGoto(cond, BB_ifTrue);
348          BB_ifFalse: {
349            ...
350            goto BB_end            // should be generated in BB_ifFalse
351          }
352          BB_ifTrue: {...}
353          BB_end: {...}
354      */
355     Stmt &CondGoto(Expr cond, BB &target, bool inverseCond = false);
356 
357     /* using SwitchBuilder interface for switch statement creation
358          auto switchStmt = Switch(type, cond, defaultBB)
359                              .Case(0, bb1)
360                              .Case(1, bb2)
361                              .Done();
362      */
363 
364     // when result is nullptr, don't need the result (or no result)
365     Stmt &Call(Function &func, Args &args, PregIdx pregIdx);
366 
367     Stmt &PureCall(Expr funcAddr, Args &args, Var *result = nullptr);
368 
369     Stmt &ICall(Expr funcAddr, Args &args, Var *result = nullptr);
370 
371     Stmt &ICall(Expr funcAddr, Args &args, PregIdx pregIdx);
372 
373     // when result is nullptr, don't need the result (or no result)
374     Stmt &IntrinsicCall(IntrinsicId func, Args &valueArgs, Var *result = nullptr);
375 
376     Stmt &IntrinsicCall(IntrinsicId func, Args &valueArgs, PregIdx retPregIdx1, PregIdx retPregIdx2);
377 
378     Stmt &Return(Expr returnVal);
379 
380     // debug info
381     Stmt &Comment(std::string comment);
382 
383     Stmt &Dassign(Expr src, Var &var, FieldId fieldId = 0);
384     Stmt &Iassign(Expr src, Expr addr, Type *baseType, FieldId fieldId = 0);
385 
386     // expressions
387     Expr Dread(Var &var);  // do we need other forms?
Dread(Var * var)388     inline Expr Dread(Var *var)
389     {  // shortcut for read from local-var
390         CHECK_NULL_FATAL(var);
391         return Dread(*var);
392     }
393 
394     Expr IntrinsicOp(IntrinsicId id, Type *type, Args &args_);
395     Expr Iread(Type *type, Expr addr, Type *baseType, FieldId fieldId = 0);
396     PregIdx CreatePreg(Type *mtype);
397     Stmt &Regassign(Expr src, PregIdx reg);
398     Expr Regread(PregIdx pregIdx);
399     Expr ConstVal(Const &constVal);  // a const operand
400 
401     Expr Lnot(Type *type, Expr src);
402     Expr Bnot(Type *type, Expr src);
403     Expr Sqrt(Type *type, Expr src);
404     Expr Ceil(Type *type, Expr src);
405     Expr Abs(Type *type, Expr src);
406 
407     Expr Add(Type *type, Expr src1, Expr src2);
408     Expr Sub(Type *type, Expr src1, Expr src2);
409     Expr Mul(Type *type, Expr src1, Expr src2);
410     Expr UDiv(Type *type, Expr src1, Expr src2);  // unsigned
411     Expr SDiv(Type *type, Expr src1, Expr src2);  // signed
412     Expr SRem(Type *type, Expr src1, Expr src2);  // signed
413     Expr Shl(Type *type, Expr src1, Expr src2);
414     Expr LShr(Type *type, Expr src1, Expr src2);
415     Expr AShr(Type *type, Expr src1, Expr src2);
416     Expr And(Type *type, Expr src1, Expr src2);
417     Expr Or(Type *type, Expr src1, Expr src2);
418     Expr Xor(Type *type, Expr src1, Expr src2);
419     Expr Max(Type *type, Expr src1, Expr src2);
420     Expr Min(Type *type, Expr src1, Expr src2);
421 
422     Expr ICmp(Type *type, Expr src1, Expr src2, IntCmpCondition cond);
423     Expr FCmp(Type *type, Expr src1, Expr src2, FloatCmpCondition cond);
424 
425     // Type conversion
426     // Type of opnd should be consistent with fromType: no implicient conversion
427     Expr Trunc(Type *fromType, Type *toType, Expr opnd);
428     Expr ZExt(Type *fromType, Type *toType, Expr opnd);
429     Expr SExt(Type *fromType, Type *toType, Expr opnd);
430     Expr BitCast(Type *fromType, Type *toType, Expr opnd);
431     Expr Cvt(Type *fromType, Type *toType, Expr opnd);
432     Expr Floor(Type *fromType, Type *toType, Expr opnd);
433     Expr Ceil(Type *fromType, Type *toType, Expr opnd);
434 
435     void SetFuncFrameResverdSlot(int slot);
436     void SetFuncFramePointer(const String &val);
437     void SetCurrentDebugComment(const std::string& comment);
438     void ClearCurrentDebugComment();
439 
440 public:
441     // helper classes for compound IR entity building
442     class SwitchBuilder {
443     public:
SwitchBuilder(LMIRBuilder & builder_,Type * type_,Expr cond_,BB & defaultBB_)444         SwitchBuilder(LMIRBuilder &builder_, Type *type_, Expr cond_, BB &defaultBB_)
445             : builder(builder_), type(type_), cond(cond_), defaultBB(defaultBB_)
446         {
447         }
448 
Case(int64_t value,BB & bb)449         SwitchBuilder &Case(int64_t value, BB &bb)
450         {
451             cases.push_back(std::make_pair(value, &bb));
452             return *this;
453         }
454 
Done()455         Stmt &Done()
456         {
457             return builder.CreateSwitchInternal(type, cond, defaultBB, cases);
458         }
459 
460     private:
461         LMIRBuilder &builder;
462         Type *type;
463         Expr cond;
464         BB &defaultBB;
465         std::vector<std::pair<int64_t, BB *>> cases;
466     };
467 
Switch(Type * type,Expr cond,BB & defaultBB)468     SwitchBuilder Switch(Type *type, Expr cond, BB &defaultBB)
469     {
470         return SwitchBuilder(*this, type, cond, defaultBB);
471     }
472 
473     class FunctionBuilder {
474     public:
FunctionBuilder(LMIRBuilder & builder_,const String & name_,bool needBody_)475         FunctionBuilder(LMIRBuilder &builder_, const String &name_, bool needBody_)
476             : builder(builder_), name(name_), needBody(needBody_)
477         {
478             attr = FUNC_internal;
479             convAttr = CCall;
480             isVargs = false;
481         }
482 
483         // optional: indicate the function has variable args
Vargs()484         FunctionBuilder &Vargs()
485         {
486             isVargs = true;
487             return *this;
488         }
489 
Param(Type * type,const String paramName)490         FunctionBuilder &Param(Type *type, const String paramName)
491         {
492             params.push_back(std::make_pair(paramName, type));
493             return *this;
494         }
495 
496         // optional: if not called, return nothing (return void)
Return(Type * type)497         FunctionBuilder &Return(Type *type)
498         {
499             retType = type;
500             return *this;
501         }
502 
503         // optional: if not called, default to FUNC_local
Attribute(FuncAttr attr_)504         FunctionBuilder &Attribute(FuncAttr attr_)
505         {
506             attr = attr_;
507             return *this;
508         }
509 
510         // optional: if not called, default to Func_CCall
CallConvAttribute(ConvAttr convAttr_)511         FunctionBuilder &CallConvAttribute(ConvAttr convAttr_)
512         {
513             convAttr = convAttr_;
514             return *this;
515         }
516 
Done()517         Function &Done()
518         {
519             return builder.CreateFunctionInternal(name, retType, params, isVargs, needBody, attr, convAttr);
520         }
521 
522     private:
523         LMIRBuilder &builder;
524         const String &name;
525         Type *retType;
526         FuncAttr attr;
527         ConvAttr convAttr;
528         bool isVargs;
529         bool needBody;  // indicate whether is a declaration or definition.
530         Params params;
531     };
532 
533     // only declare the function in current module (means it's an external function)
DeclareFunction(const String & name)534     FunctionBuilder DeclareFunction(const String &name)
535     {
536         return FunctionBuilder(*this, name, false);
537     }
538 
539     // define the function in current module
DefineFunction(const String & name)540     FunctionBuilder DefineFunction(const String &name)
541     {
542         return FunctionBuilder(*this, name, true);
543     }
544 
545 public:
546     // builtin types: primitive types (all MIR primitive types except PTY_ptr)
547     Type *i8Type;
548     Type *i16Type;
549     Type *i32Type;
550     Type *i64Type;
551     Type *u1Type;
552     Type *u8Type;
553     Type *u16Type;
554     Type *u32Type;
555     Type *u64Type;
556     Type *voidType;
557     Type *f32Type;
558     Type *f64Type;
559 
560     // builtin types: commonly used derived types
561     Type *strType;
562     Type *i64PtrType;
563     Type *i64RefType;
564     Type *i64RefRefType;
565 
566 private:
567     Stmt &CreateSwitchInternal(Type *type, Expr cond, BB &defaultBB, std::vector<std::pair<int64_t, BB *>> &cases);
568     void AddConstItemInternal(StructConst &structConst, FieldId fieldId, Const &field);
569     void AddConstItemInternal(ArrayConst &structConst, Const &element);
570     Function &CreateFunctionInternal(const String &name, Type *retType, Params &params, bool isVargs, bool needBody,
571                                      FuncAttr attr, ConvAttr convAttr);
572 
573 private:
574     MIRBuilder &mirBuilder;  // The real IR-builder: current implementation
575     Module &module;          // and the module to process
576 };
577 
578 }  // namespace litecg
579 }  // namespace maple
580 #endif  // MAPLE_LITECG_LMIR_BUILDER_H
581