• 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 MIRStructType;
52 class MIRArrayType;
53 class MIRFuncType;
54 class MIRConst;
55 class MIRAggConst;
56 class MIRSymbol;
57 class StmtNode;
58 class BaseNode;
59 class BlockNode;
60 class MIRPreg;
61 
62 namespace litecg {
63 
64 // Our type abstraction. currently delegate to MIR
65 
66 using String = std::string;
67 
68 using Module = MIRModule;
69 using Function = MIRFunction;
70 
71 // Note: Type is base class of all other Types
72 using Type = MIRType;              // base class of all Types
73 using StructType = MIRStructType;  //    |__ StructType
74 using ArrayType = MIRArrayType;
75 using Const = MIRConst;
76 using StructConst = MIRAggConst;
77 using ArrayConst = MIRAggConst;
78 using Var = MIRSymbol;
79 using Stmt = StmtNode;
80 using BB = BlockNode;  // A temporary faked BB
81 
82 using Param = std::pair<const String, Type *>;
83 using Params = std::vector<Param>;
84 using FieldOffset = std::pair<int32_t, int32_t>;  // (byteoffset, bitoffset)
85 using PregIdx = int32_t;
86 
87 // enumerations
88 enum class MIRIntrinsic {
89 #define DEF_MIR_INTRINSIC(STR, NAME, INTRN_CLASS, RETURN_TYPE, ...) INTRN_##STR,
90 #include "intrinsics.def"
91 #undef DEF_MIR_INTRINSIC
92 };
93 using IntrinsicId = MIRIntrinsic;
94 /* available intrinsic should be list here. like:
95    INTRN_memcpy, INTRN_memset, etc.
96  */
97 class Expr {
98 public:
Expr(BaseNode * baseNode,Type * nodeType)99     Expr(BaseNode *baseNode, Type *nodeType) : node(baseNode), type(nodeType) {}
100 
Expr()101     Expr() : node(nullptr), type(nullptr) {}
102 
103     ~Expr() = default;
104 
GetNode()105     BaseNode *GetNode()
106     {
107         return node;
108     }
109 
GetNode()110     BaseNode *GetNode() const
111     {
112         return node;
113     }
114 
GetType()115     Type *GetType()
116     {
117         return type;
118     }
119 
GetType()120     Type *GetType() const
121     {
122         return type;
123     }
124 
125     bool IsDread() const;
126     bool IsRegread() const;
127     bool IsConstValue() const;
128 
129 private:
130     BaseNode *node;
131     Type *type;
132 };
133 
134 enum LiteCGValueKind {
135     kPregKind,
136     kSymbolKind,
137     kConstKind,
138     kGlueAdd,
139 };
140 
141 struct LiteCGValue {
142     LiteCGValueKind kind;
143     std::variant<PregIdx, MIRSymbol*, MIRConst*> data;
144 };
145 
146 using Args = std::vector<Expr>;
147 
148 enum FuncAttr {     // visibility of the defined function
149     FUNC_global,    // function has global visibility
150     FUNC_weak,      // weak function defined in this module
151     FUNC_internal,  // function defined and only used in this module
152 };
153 
154 enum GlobalRegister {
155     kSregSp = -1,
156     kSregFp = -2,
157 };
158 
159 enum ConvAttr {
160     CCall,
161     Web_Kit_JS_Call,
162     GHC_Call,
163 };
164 
165 enum GlobalVarAttr {
166     VAR_external,  // global variable declaration (no definition)
167     VAR_weak,      // weak function defined in this module
168     VAR_internal,  // variable defined and only used in this module
169     VAR_global,    // exported variable defined in this module
170     VAR_readonly,  // this is additional flag, default is R/W
171 };
172 
173 enum IntCmpCondition {
174     kEQ,
175     kNE,
176     kULT,
177     kULE,
178     kUGT,
179     kUGE,
180     kSLT,
181     kSLE,
182     kSGT,
183     kSGE,
184 };
185 
186 enum FloatCmpCondition {
187     kOLT,
188     kOLE,
189     kOGT,
190     kOGE,
191     kONE,
192     kOEQ,
193 };
194 
195 enum LiteCGTypeKind {
196     kLiteCGTypeInvalid,
197     kLiteCGTypeUnknown,
198     kLiteCGTypeScalar,
199     kLiteCGTypeBitField,
200     kLiteCGTypeArray,
201     kLiteCGTypeFArray,
202     kLiteCGTypeJArray,
203     kLiteCGTypeStruct,
204     kLiteCGTypeUnion,
205     kLiteCGTypeClass,
206     kLiteCGTypeInterface,
207     kLiteCGTypeStructIncomplete,
208     kLiteCGTypeClassIncomplete,
209     kLiteCGTypeConstString,
210     kLiteCGTypeInterfaceIncomplete,
211     kLiteCGTypePointer,
212     kLiteCGTypeFunction,
213     kLiteCGTypeVoid,
214     kLiteCGTypeByName,
215     kLiteCGTypeParam,
216     kLiteCGTypeInstantVector,
217     kLiteCGTypeGenericInstant,
218 };
219 
220 // FieldAttr: do we need to support volatile here?
221 // using FieldAttr = AttrKind
222 /* used attribute for field:
223    ATTR_volatile
224  */
225 
226 using FieldId = uint32_t;
227 /* Use FieldId from MIR directly: it's a uint32_t, but with special meaning
228    for FieldId == 0: refer to the "whole" of the type
229    To avoid conflict with MIR type define, here using type name "FieldId"
230  */
231 
232 Module *CreateModuleWithName(const std::string &name);
233 void ReleaseModule(Module *module);
234 
235 /**
236  * a simplified, specialized MapleIR builder for LiteCG
237  * The basic IR set
238  *
239  * General rule for the interface:
240  *  + if function returns value type, then returns type is value type
241  *  + otherwise if the return value can be null, return type is pointer
242  *    caller should check for null
243  *  + otherwise the return type is reference.
244  *
245  *  + for compound IR (need to be constructed with a sequence of calls,
246  *      e.g., struct type/const, array const, function, switch), using
247  *    specific builder class to do the "chained" construction.
248  *
249  */
250 class LMIRBuilder {
251 public:
252     LMIRBuilder(Module &module);
253     ~LMIRBuilder() = default;
254 
255     void DumpIRToFile(const std::string fileName);
256 
257     LiteCGTypeKind LiteCGGetTypeKind(Type *type) const;
258     void SetCallStmtDeoptBundleInfo(Stmt &icallNode, const std::unordered_map<int, LiteCGValue> &deoptBundleInfo);
259 
260     // Type creation (currently all in global scope)
261     /*
262        For primitive types, using LMIRBuilder's public member:
263        i8Type, u8Type, etc.
264      */
265 
266     // derived type creation
267     Type *CreatePtrType(Type *mirType);
268     Type *CreateRefType(Type *mirType);
269 
270     bool IsHeapPointerType(Type *mirType) const;
271 
272     // (multi-dim) array of fixed size array
273     ArrayType *CreateArrayType(Type *elemType, std::vector<uint32_t> &dimSize);
274 
275     /* using StructTypeBuilder interface for StructType creation
276          auto structType = CreateStructType("mystruct")
277                              .Field("field1", i32Type)
278                              .Field("field2", i64Type)
279                              .Done();
280      */
281     Type *GetStructType(const String &name);  // query for existing struct type
282 
283     // usage of this function has precondition, should be documented
284     FieldOffset GetFieldOffset(StructType *structType, FieldId fieldId);
285 
286     // for function pointer
287     Type *CreateFuncType(std::vector<Type *> params, Type *retType, bool isVarg);
288 
289     Type *LiteCGGetPointedType(Type *type);
290 
291     std::vector<Type *> LiteCGGetFuncParamTypes(Type *type);
292 
293     Type *LiteCGGetFuncReturnType(Type *type);
294     // still need interface for AddressOfFunction
295 
296     // Function declaration and definition
297     /* using FunctionBuilder interface for Function creation:
298          // i32 myfunc(i32 param1, i64 param2) { }
299          auto structType = DefineFunction("myfunc")
300                              .Param(i32Type, "param1")
301                              .Param(i64Type, "param2")
302                              .Ret(i32Type)               // optional for void
303                              .Done();
304 
305          auto structType = DeclareFunction("myfunc1")
306                              .Param(i32Type, "param1")
307                              .Param(i64Type, "param2")
308                              .Ret(i32Type)
309                              .Done();
310      */
311 
312     // This is to enable forwarded call before its definition
313     // can return null. caller should check for null.
314     Function *GetFunc(const String &name);  // get a function by its unique name
315 
316     // when a function is set as current function (of the module), local
317     // declarations and statements are insert into it.
318     void SetCurFunc(Function &function);
319 
320     Function &GetCurFunction() const;
321 
322     void RenameFormal2Preg(Function &func);
323 
324     MIRPreg *LiteCGGetPreg(Function &func, int32_t pRegNo);
325     Expr LiteCGGetPregFP(Function &func);
326     Expr LiteCGGetPregSP();
327 
328     // var creation
329     // refine the interface for attributes here. and also storage-class?
330     // initialized to zero if defined here, by default not exported
331     Var &CreateGlobalVar(Type *type, const String &name, GlobalVarAttr attr = VAR_internal);
332     // initialized to const, by default not exported
333     Var &CreateGlobalVar(Type *type, const String &name, Const &init, GlobalVarAttr attr = VAR_internal);
334     Var *GetGlobalVar(const String &name);
335 
336     Var &CreateLocalVar(Type *type, const String &name);
337     Var *GetLocalVar(const String &name);
338     Var *GetLocalVarFromExpr(Expr inExpr);
339     void SetFunctionDerived2BaseRef(PregIdx derived, PregIdx base);
340     PregIdx GetPregIdxFromExpr(const Expr &expr);
341     Var &GetParam(Function &function, size_t index) const;
342     Expr GenExprFromVar(Var &var);
343 
344     Const &CreateIntConst(Type *type, int64_t val);
345     Const &CreateFloatConst(float val);
346     Const &CreateDoubleConst(double val);
347     Const &CreateStrConst(const String &constStr);
348     Const *GetConstFromExpr(const Expr &expr);
349 
350     // In MIR, the const for struct & array are the same. But we separate it here.
351     /* using StructConstBuilder interface for StructConst creation:
352          auto structConst = CreateStructConst(structType)
353                               .Field(1, CreateIntConst(i32Type, 0))
354                               .Filed(2, CreateIntConst(i64Type, 0))
355                               .Done();
356      */
357 
358     /* using ArrayConstBuilder interface for ArrayConst creation:
359        Note: the elements should be added consequentially, and match the dim size.
360          auto arrayConst = CreateArrayConst(arrayType)
361                               .Element(CreateIntConst(i32Type, 0))
362                               .Element(CreateIntConst(i32Type, 0))
363                               .Done();
364        or using the following form:
365          auto arrayConst = CreateArrayConst(arrayType).Dim({0, 0}).Done();
366      */
367 
368     /*
369       BB is the container node for a sequence or linear statements,
370       if needLabel == true, implicitly create a label node as its first statement.
371       BB also servers as target for Gotos, when it's a goto target, it
372       should have needLabel == true
373      */
374     BB &CreateBB(bool needLabel = true);
375     void AppendStmt(BB &bb, Stmt &stmt);              // append stmt to the back of BB
376     void AppendStmtBeforeBranch(BB &bb, Stmt &stmt);  // append stmt after the first non-jump stmt in back of BB
377     bool IsEmptyBB(BB &bb);
378     void AppendBB(BB &bb);    // append BB to the back of current function;
379     void AppendToLast(BB &bb);
380     BB &GetLastPosBB();
381     BB &GetLastAppendedBB();  // get last appended BB of current function
382 
383     void SetStmtCallConv(Stmt &stmt, ConvAttr convAttr);
384 
385     // statements
386     Stmt &Goto(BB &dest);  // jump without condition
387     /* conditional goto:
388        when inverseCond == true, using (!cond) as condition
389 
390        1. if(cond)-then form code should be generated this way:
391 
392          if(!cond) goto BB_end    // CondGoto(cond, BB_end, true);
393          BB_ifTrue: {...}
394          BB_end: {...}
395 
396        2. if-then-else form code should be generated this way:
397          if(cond) goto BB_ifTrue  // CondGoto(cond, BB_ifTrue);
398          BB_ifFalse: {
399            ...
400            goto BB_end            // should be generated in BB_ifFalse
401          }
402          BB_ifTrue: {...}
403          BB_end: {...}
404      */
405     Stmt &CondGoto(Var &cond, BB &target, bool inverseCond = false);
406     Stmt &CondGoto(Expr cond, BB &target, bool inverseCond = false);
407 
408     /* using SwitchBuilder interface for switch statement creation
409          auto switchStmt = Switch(type, cond, defaultBB)
410                              .Case(0, bb1)
411                              .Case(1, bb2)
412                              .Done();
413      */
414 
415     // when result is nullptr, don't need the result (or no result)
416     Stmt &Call(Function &func, Args &args, Var *result = nullptr);
417 
418     Stmt &Call(Function &func, Args &args, PregIdx pregIdx);
419 
420     Stmt &ICall(Expr funcAddr, Args &args, Var *result = nullptr);
421 
422     Stmt &ICall(Expr funcAddr, Args &args, PregIdx pregIdx);
423 
424     // when result is nullptr, don't need the result (or no result)
425     Stmt &IntrinsicCall(IntrinsicId func, Args &valueArgs, Var *result = nullptr);
426 
427     Stmt &Return(Expr returnVal);
428 
429     // debug info
430     Stmt &Comment(std::string comment);
431 
432     Stmt &Dassign(Expr src, Var &var, FieldId fieldId = 0);
433     Stmt &Iassign(Expr src, Expr addr, Type *baseType, FieldId fieldId = 0);
434 
435     // expressions
436     Expr Dread(Var &var);  // do we need other forms?
Dread(Var * var)437     inline Expr Dread(Var *var)
438     {  // shortcut for read from local-var
439         CHECK_NULL_FATAL(var);
440         return Dread(*var);
441     }
442 
443     Expr DreadWithField(Var &var, FieldId id);
444     Expr IntrinsicOp(IntrinsicId id, Type *type, Args &args_);
445     Expr Iread(Type *type, Expr addr, Type *baseType, FieldId fieldId = 0);
446     PregIdx CreatePreg(Type *mtype);
447     Stmt &Regassign(Expr src, PregIdx reg);
448     Expr Regread(PregIdx pregIdx);
449     Expr Addrof(Var &var);           // do we need other forms?
450     Expr ConstVal(Const &constVal);  // a const operand
451 
452     Expr Lnot(Type *type, Expr src);
453     Expr Bnot(Type *type, Expr src);
454     Expr Sqrt(Type *type, Expr src);
455     Expr Ceil(Type *type, Expr src);
456     Expr Abs(Type *type, Expr src);
457 
458     Expr Add(Type *type, Expr src1, Expr src2);
459     Expr Sub(Type *type, Expr src1, Expr src2);
460     Expr Mul(Type *type, Expr src1, Expr src2);
461     Expr UDiv(Type *type, Expr src1, Expr src2);  // unsigned
462     Expr SDiv(Type *type, Expr src1, Expr src2);  // signed
463     Expr URem(Type *type, Expr src1, Expr src2);  // unsigned
464     Expr SRem(Type *type, Expr src1, Expr src2);  // signed
465     Expr Shl(Type *type, Expr src1, Expr src2);
466     Expr LShr(Type *type, Expr src1, Expr src2);
467     Expr AShr(Type *type, Expr src1, Expr src2);
468     Expr And(Type *type, Expr src1, Expr src2);
469     Expr Or(Type *type, Expr src1, Expr src2);
470     Expr Xor(Type *type, Expr src1, Expr src2);
471     Expr Max(Type *type, Expr src1, Expr src2);
472     Expr Min(Type *type, Expr src1, Expr src2);
473 
474     Expr ICmpEQ(Type *type, Expr src1, Expr src2);
475     Expr ICmpNE(Type *type, Expr src1, Expr src2);
476     // unsigned compare
477     Expr ICmpULT(Type *type, Expr src1, Expr src2);
478     Expr ICmpULE(Type *type, Expr src1, Expr src2);
479     Expr ICmpUGT(Type *type, Expr src1, Expr src2);
480     Expr ICmpUGE(Type *type, Expr src1, Expr src2);
481     // signed compare
482     Expr ICmpSLT(Type *type, Expr src1, Expr src2);
483     Expr ICmpSLE(Type *type, Expr src1, Expr src2);
484     Expr ICmpSGT(Type *type, Expr src1, Expr src2);
485     Expr ICmpSGE(Type *type, Expr src1, Expr src2);
486     Expr ICmp(Type *type, Expr src1, Expr src2, IntCmpCondition cond);
487     Expr FCmp(Type *type, Expr src1, Expr src2, FloatCmpCondition cond);
488 
489     // Type conversion
490     // Type of opnd should be consistent with fromType: no implicient conversion
491     Expr Trunc(Type *fromType, Type *toType, Expr opnd);
492     Expr ZExt(Type *fromType, Type *toType, Expr opnd);
493     Expr SExt(Type *fromType, Type *toType, Expr opnd);
494     Expr BitCast(Type *fromType, Type *toType, Expr opnd);
495     Expr Cvt(Type *fromType, Type *toType, Expr opnd);
496     Expr Floor(Type *fromType, Type *toType, Expr opnd);
497     Expr Ceil(Type *fromType, Type *toType, Expr opnd);
498 
499     Expr Select(Type *type, Expr cond, Expr ifTrue, Expr ifFalse);
500 
501     void SetFuncFrameResverdSlot(int slot);
502     void SetFuncFramePointer(const String &val);
503     void SetCurrentDebugComment(const std::string& comment);
504     void ClearCurrentDebugComment();
505 
506 public:
507     // helper classes for compound IR entity building
508     class SwitchBuilder {
509     public:
SwitchBuilder(LMIRBuilder & builder_,Type * type_,Expr cond_,BB & defaultBB_)510         SwitchBuilder(LMIRBuilder &builder_, Type *type_, Expr cond_, BB &defaultBB_)
511             : builder(builder_), type(type_), cond(cond_), defaultBB(defaultBB_)
512         {
513         }
514 
Case(int64_t value,BB & bb)515         SwitchBuilder &Case(int64_t value, BB &bb)
516         {
517             cases.push_back(std::make_pair(value, &bb));
518             return *this;
519         }
520 
Done()521         Stmt &Done()
522         {
523             return builder.CreateSwitchInternal(type, cond, defaultBB, cases);
524         }
525 
526     private:
527         LMIRBuilder &builder;
528         Type *type;
529         Expr cond;
530         BB &defaultBB;
531         std::vector<std::pair<int64_t, BB *>> cases;
532     };
533 
Switch(Type * type,Expr cond,BB & defaultBB)534     SwitchBuilder Switch(Type *type, Expr cond, BB &defaultBB)
535     {
536         return SwitchBuilder(*this, type, cond, defaultBB);
537     }
538 
539     class StructTypeBuilder {
540     public:
StructTypeBuilder(LMIRBuilder & builder_,const String & name_)541         StructTypeBuilder(LMIRBuilder &builder_, const String &name_) : builder(builder_), name(name_) {}
542 
Field(std::string_view fieldName,Type * fieldType)543         StructTypeBuilder &Field(std::string_view fieldName, Type *fieldType)
544         {
545             // field type attribute?
546             fields.push_back(std::make_pair(fieldName, fieldType));
547             return *this;
548         }
549 
Done()550         Type *Done()
551         {
552             return builder.CreateStructTypeInternal(name, fields);
553         }
554 
555     private:
556         LMIRBuilder &builder;
557         const String &name;
558         std::vector<std::pair<std::string_view, Type *>> fields;
559     };
560 
CreateStructType(const String & name)561     StructTypeBuilder CreateStructType(const String &name)
562     {
563         return StructTypeBuilder(*this, name);
564     }
565 
566     class StructConstBuilder {
567     public:
StructConstBuilder(LMIRBuilder & builder_,StructType * type_)568         StructConstBuilder(LMIRBuilder &builder_, StructType *type_) : builder(builder_)
569         {
570             structConst = &builder_.CreateStructConstInternal(type_);
571         }
572 
Field(FieldId fieldId,Const & field)573         StructConstBuilder &Field(FieldId fieldId, Const &field)
574         {
575             builder.AddConstItemInternal(*structConst, fieldId, field);
576             return *this;
577         }
578 
Done()579         StructConst &Done()
580         {
581             return *structConst;
582         }
583 
584     private:
585         LMIRBuilder &builder;
586         StructConst *structConst;
587     };
588 
CreateStructConst(StructType * type)589     StructConstBuilder CreateStructConst(StructType *type)
590     {
591         return StructConstBuilder(*this, type);
592     }
593 
594     class ArrayConstBuilder {
595     public:
ArrayConstBuilder(LMIRBuilder & builder_,ArrayType * type_)596         ArrayConstBuilder(LMIRBuilder &builder_, ArrayType *type_) : builder(builder_)
597         {
598             arrayConst = &builder.CreateArrayConstInternal(type_);
599         }
600 
Element(Const & element)601         ArrayConstBuilder &Element(Const &element)
602         {
603             builder.AddConstItemInternal(*arrayConst, element);
604             return *this;
605         }
606 
607         template <class T>
Dim(const std::vector<T> init)608         ArrayConstBuilder &Dim(const std::vector<T> init)
609         {
610             for (const auto &value : init) {
611                 // fix the element type.
612                 Const &element = builder.CreateIntConst(builder.i32Type, static_cast<int64_t>(value));
613                 Element(element);
614             }
615             return *this;
616         }
617 
618         template <class T>
Dim(std::initializer_list<T> literal)619         ArrayConstBuilder &Dim(std::initializer_list<T> literal)
620         {
621             return Dim(std::vector<T>(literal));
622         }
623 
Done()624         ArrayConst &Done()
625         {
626             return *arrayConst;
627         }
628 
629     private:
630         LMIRBuilder &builder;
631         ArrayConst *arrayConst;
632     };
633 
CreateArrayConst(ArrayType * type)634     ArrayConstBuilder CreateArrayConst(ArrayType *type)
635     {
636         return ArrayConstBuilder(*this, type);
637     }
638 
639     class FunctionBuilder {
640     public:
FunctionBuilder(LMIRBuilder & builder_,const String & name_,bool needBody_)641         FunctionBuilder(LMIRBuilder &builder_, const String &name_, bool needBody_)
642             : builder(builder_), name(name_), needBody(needBody_)
643         {
644             attr = FUNC_internal;
645             convAttr = CCall;
646             isVargs = false;
647         }
648 
649         // optional: indicate the function has variable args
Vargs()650         FunctionBuilder &Vargs()
651         {
652             isVargs = true;
653             return *this;
654         }
655 
Param(Type * type,const String paramName)656         FunctionBuilder &Param(Type *type, const String paramName)
657         {
658             params.push_back(std::make_pair(paramName, type));
659             return *this;
660         }
661 
662         // optional: if not called, return nothing (return void)
Return(Type * type)663         FunctionBuilder &Return(Type *type)
664         {
665             retType = type;
666             return *this;
667         }
668 
669         // optional: if not called, default to FUNC_local
Attribute(FuncAttr attr_)670         FunctionBuilder &Attribute(FuncAttr attr_)
671         {
672             attr = attr_;
673             return *this;
674         }
675 
676         // optional: if not called, default to Func_CCall
CallConvAttribute(ConvAttr convAttr_)677         FunctionBuilder &CallConvAttribute(ConvAttr convAttr_)
678         {
679             convAttr = convAttr_;
680             return *this;
681         }
682 
Done()683         Function &Done()
684         {
685             return builder.CreateFunctionInternal(name, retType, params, isVargs, needBody, attr, convAttr);
686         }
687 
688     private:
689         LMIRBuilder &builder;
690         const String &name;
691         Type *retType;
692         FuncAttr attr;
693         ConvAttr convAttr;
694         bool isVargs;
695         bool needBody;  // indicate whether is a declaration or definition.
696         Params params;
697     };
698 
699     // only declare the function in current module (means it's an external function)
DeclareFunction(const String & name)700     FunctionBuilder DeclareFunction(const String &name)
701     {
702         return FunctionBuilder(*this, name, false);
703     }
704 
705     // define the function in current module
DefineFunction(const String & name)706     FunctionBuilder DefineFunction(const String &name)
707     {
708         return FunctionBuilder(*this, name, true);
709     }
710 
711 public:
712     // builtin types: primitive types (all MIR primitive types except PTY_ptr)
713     Type *i8Type;
714     Type *i16Type;
715     Type *i32Type;
716     Type *i64Type;
717     Type *i128Type;
718     Type *u1Type;
719     Type *u8Type;
720     Type *u16Type;
721     Type *u32Type;
722     Type *u64Type;
723     Type *u128Type;
724     Type *voidType;
725     Type *f32Type;
726     Type *f64Type;
727 
728     // builtin types: commonly used derived types
729     Type *strType;
730     Type *i64PtrType;
731     Type *i64RefType;
732     Type *i64RefRefType;
733 
734 private:
735     Stmt &CreateSwitchInternal(Type *type, Expr cond, BB &defaultBB, std::vector<std::pair<int64_t, BB *>> &cases);
736     Type *CreateStructTypeInternal(const String &name, std::vector<std::pair<std::string_view, Type *>> &fields);
737     StructConst &CreateStructConstInternal(StructType *type);
738     void AddConstItemInternal(StructConst &structConst, FieldId fieldId, Const &field);
739     void AddConstItemInternal(ArrayConst &structConst, Const &element);
740     ArrayConst &CreateArrayConstInternal(ArrayType *type);
741     Function &CreateFunctionInternal(const String &name, Type *retType, Params &params, bool isVargs, bool needBody,
742                                      FuncAttr attr, ConvAttr convAttr);
743 
744 private:
745     MIRBuilder &mirBuilder;  // The real IR-builder: current implementation
746     Module &module;          // and the module to process
747 };
748 
749 }  // namespace litecg
750 }  // namespace maple
751 #endif  // MAPLE_LITECG_LMIR_BUILDER_H
752