• 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 &DeoptCall(Function &func, Args &args);
366 
367     Stmt &TailICall(Expr funcAddr, Args &args);
368 
369     Stmt &PureCall(Expr funcAddr, Args &args, Var *result = nullptr);
370 
371     Stmt &ICall(Expr funcAddr, Args &args, Var *result = nullptr);
372 
373     Stmt &ICall(Expr funcAddr, Args &args, PregIdx pregIdx);
374 
375     // when result is nullptr, don't need the result (or no result)
376     Stmt &IntrinsicCall(IntrinsicId func, Args &valueArgs, Var *result = nullptr);
377 
378     Stmt &IntrinsicCall(IntrinsicId func, Args &valueArgs, PregIdx retPregIdx1, PregIdx retPregIdx2);
379 
380     Stmt &Return(Expr returnVal);
381 
382     // debug info
383     Stmt &Comment(std::string comment);
384 
385     Stmt &Dassign(Expr src, Var &var, FieldId fieldId = 0);
386     Stmt &Iassign(Expr src, Expr addr, Type *baseType, FieldId fieldId = 0);
387 
388     // expressions
389     Expr Dread(Var &var);  // do we need other forms?
Dread(Var * var)390     inline Expr Dread(Var *var)
391     {  // shortcut for read from local-var
392         CHECK_NULL_FATAL(var);
393         return Dread(*var);
394     }
395 
396     Expr IntrinsicOp(IntrinsicId id, Type *type, Args &args_);
397     Expr Iread(Type *type, Expr addr, Type *baseType, FieldId fieldId = 0);
398     PregIdx CreatePreg(Type *mtype);
399     Stmt &Regassign(Expr src, PregIdx reg);
400     Expr Regread(PregIdx pregIdx);
401     Expr ConstVal(Const &constVal);  // a const operand
402 
403     Expr Lnot(Type *type, Expr src);
404     Expr Bnot(Type *type, Expr src);
405     Expr Sqrt(Type *type, Expr src);
406     Expr Ceil(Type *type, Expr src);
407     Expr Abs(Type *type, Expr src);
408 
409     Expr Add(Type *type, Expr src1, Expr src2);
410     Expr Sub(Type *type, Expr src1, Expr src2);
411     Expr Mul(Type *type, Expr src1, Expr src2);
412     Expr UDiv(Type *type, Expr src1, Expr src2);  // unsigned
413     Expr SDiv(Type *type, Expr src1, Expr src2);  // signed
414     Expr SRem(Type *type, Expr src1, Expr src2);  // signed
415     Expr Shl(Type *type, Expr src1, Expr src2);
416     Expr LShr(Type *type, Expr src1, Expr src2);
417     Expr AShr(Type *type, Expr src1, Expr src2);
418     Expr And(Type *type, Expr src1, Expr src2);
419     Expr Or(Type *type, Expr src1, Expr src2);
420     Expr Xor(Type *type, Expr src1, Expr src2);
421     Expr Max(Type *type, Expr src1, Expr src2);
422     Expr Min(Type *type, Expr src1, Expr src2);
423 
424     Expr ICmp(Type *type, Expr src1, Expr src2, IntCmpCondition cond);
425     Expr FCmp(Type *type, Expr src1, Expr src2, FloatCmpCondition cond);
426 
427     // Type conversion
428     // Type of opnd should be consistent with fromType: no implicient conversion
429     Expr Trunc(Type *fromType, Type *toType, Expr opnd);
430     Expr ZExt(Type *fromType, Type *toType, Expr opnd);
431     Expr SExt(Type *fromType, Type *toType, Expr opnd);
432     Expr BitCast(Type *fromType, Type *toType, Expr opnd);
433     Expr Cvt(Type *fromType, Type *toType, Expr opnd);
434     Expr Floor(Type *fromType, Type *toType, Expr opnd);
435     Expr Ceil(Type *fromType, Type *toType, Expr opnd);
436 
437     void SetFuncFrameResverdSlot(int slot);
438     void SetFuncFramePointer(const String &val);
439     void SetCurrentDebugComment(const std::string& comment);
440     void ClearCurrentDebugComment();
441 
442 public:
443     // helper classes for compound IR entity building
444     class SwitchBuilder {
445     public:
SwitchBuilder(LMIRBuilder & builder_,Type * type_,Expr cond_,BB & defaultBB_)446         SwitchBuilder(LMIRBuilder &builder_, Type *type_, Expr cond_, BB &defaultBB_)
447             : builder(builder_), type(type_), cond(cond_), defaultBB(defaultBB_)
448         {
449         }
450 
Case(int64_t value,BB & bb)451         SwitchBuilder &Case(int64_t value, BB &bb)
452         {
453             cases.push_back(std::make_pair(value, &bb));
454             return *this;
455         }
456 
Done()457         Stmt &Done()
458         {
459             return builder.CreateSwitchInternal(type, cond, defaultBB, cases);
460         }
461 
462     private:
463         LMIRBuilder &builder;
464         Type *type;
465         Expr cond;
466         BB &defaultBB;
467         std::vector<std::pair<int64_t, BB *>> cases;
468     };
469 
Switch(Type * type,Expr cond,BB & defaultBB)470     SwitchBuilder Switch(Type *type, Expr cond, BB &defaultBB)
471     {
472         return SwitchBuilder(*this, type, cond, defaultBB);
473     }
474 
475     class FunctionBuilder {
476     public:
FunctionBuilder(LMIRBuilder & builder_,const String & name_,bool needBody_)477         FunctionBuilder(LMIRBuilder &builder_, const String &name_, bool needBody_)
478             : builder(builder_), name(name_), needBody(needBody_)
479         {
480             attr = FUNC_internal;
481             convAttr = CCall;
482             isVargs = false;
483         }
484 
485         // optional: indicate the function has variable args
Vargs()486         FunctionBuilder &Vargs()
487         {
488             isVargs = true;
489             return *this;
490         }
491 
Param(Type * type,const String paramName)492         FunctionBuilder &Param(Type *type, const String paramName)
493         {
494             params.push_back(std::make_pair(paramName, type));
495             return *this;
496         }
497 
498         // optional: if not called, return nothing (return void)
Return(Type * type)499         FunctionBuilder &Return(Type *type)
500         {
501             retType = type;
502             return *this;
503         }
504 
505         // optional: if not called, default to FUNC_local
Attribute(FuncAttr attr_)506         FunctionBuilder &Attribute(FuncAttr attr_)
507         {
508             attr = attr_;
509             return *this;
510         }
511 
512         // optional: if not called, default to Func_CCall
CallConvAttribute(ConvAttr convAttr_)513         FunctionBuilder &CallConvAttribute(ConvAttr convAttr_)
514         {
515             convAttr = convAttr_;
516             return *this;
517         }
518 
Done()519         Function &Done()
520         {
521             return builder.CreateFunctionInternal(name, retType, params, isVargs, needBody, attr, convAttr);
522         }
523 
524     private:
525         LMIRBuilder &builder;
526         const String &name;
527         Type *retType;
528         FuncAttr attr;
529         ConvAttr convAttr;
530         bool isVargs;
531         bool needBody;  // indicate whether is a declaration or definition.
532         Params params;
533     };
534 
535     // only declare the function in current module (means it's an external function)
DeclareFunction(const String & name)536     FunctionBuilder DeclareFunction(const String &name)
537     {
538         return FunctionBuilder(*this, name, false);
539     }
540 
541     // define the function in current module
DefineFunction(const String & name)542     FunctionBuilder DefineFunction(const String &name)
543     {
544         return FunctionBuilder(*this, name, true);
545     }
546 
547 public:
548     // builtin types: primitive types (all MIR primitive types except PTY_ptr)
549     Type *i8Type;
550     Type *i16Type;
551     Type *i32Type;
552     Type *i64Type;
553     Type *u1Type;
554     Type *u8Type;
555     Type *u16Type;
556     Type *u32Type;
557     Type *u64Type;
558     Type *voidType;
559     Type *f32Type;
560     Type *f64Type;
561 
562     // builtin types: commonly used derived types
563     Type *strType;
564     Type *i64PtrType;
565     Type *i64RefType;
566     Type *i64RefRefType;
567 
568 private:
569     Stmt &CreateSwitchInternal(Type *type, Expr cond, BB &defaultBB, std::vector<std::pair<int64_t, BB *>> &cases);
570     void AddConstItemInternal(StructConst &structConst, FieldId fieldId, Const &field);
571     void AddConstItemInternal(ArrayConst &structConst, Const &element);
572     Function &CreateFunctionInternal(const String &name, Type *retType, Params &params, bool isVargs, bool needBody,
573                                      FuncAttr attr, ConvAttr convAttr);
574 
575 private:
576     MIRBuilder &mirBuilder;  // The real IR-builder: current implementation
577     Module &module;          // and the module to process
578 };
579 
580 }  // namespace litecg
581 }  // namespace maple
582 #endif  // MAPLE_LITECG_LMIR_BUILDER_H
583