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 #include "isel.h"
17 #include "factory.h"
18 #include "cg.h"
19 #include "standardize.h"
20 #include <map>
21 #include <utility>
22 
23 namespace maplebe {
24 /* register,                       imm ,                         memory,                        cond */
25 #define DEF_FAST_ISEL_MAPPING_INT(SIZE)                                                                               \
26     MOperator fastIselMapI##SIZE[Operand::OperandType::kOpdPhi][Operand::OperandType::kOpdPhi] = {                    \
27         {abstract::MOP_copy_rr_##SIZE, abstract::MOP_copy_ri_##SIZE, abstract::MOP_load_##SIZE, abstract::MOP_undef}, \
28         {abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef},                         \
29         {abstract::MOP_str_##SIZE, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef},                    \
30         {abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef},                         \
31     }
32 #define DEF_FAST_ISEL_MAPPING_FLOAT(SIZE)                                                            \
33     MOperator fastIselMapF##SIZE[Operand::OperandType::kOpdPhi][Operand::OperandType::kOpdPhi] = {   \
34         {abstract::MOP_copy_ff_##SIZE, abstract::MOP_copy_fi_##SIZE, abstract::MOP_load_f_##SIZE,    \
35          abstract::MOP_undef},                                                                       \
36         {abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef},        \
37         {abstract::MOP_str_f_##SIZE, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef}, \
38         {abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef, abstract::MOP_undef},        \
39     }
40 
41 DEF_FAST_ISEL_MAPPING_INT(8);
42 DEF_FAST_ISEL_MAPPING_INT(16);
43 DEF_FAST_ISEL_MAPPING_INT(32);
44 DEF_FAST_ISEL_MAPPING_INT(64);
45 DEF_FAST_ISEL_MAPPING_FLOAT(8);
46 DEF_FAST_ISEL_MAPPING_FLOAT(16);
47 DEF_FAST_ISEL_MAPPING_FLOAT(32);
48 DEF_FAST_ISEL_MAPPING_FLOAT(64);
49 
50 #define DEF_SEL_MAPPING_TBL(SIZE)                                           \
51     MOperator SelMapping##SIZE(bool isInt, uint32 x, uint32 y)              \
52     {                                                                       \
53         return isInt ? fastIselMapI##SIZE[x][y] : fastIselMapF##SIZE[x][y]; \
54     }
55 #define USE_SELMAPPING_TBL(SIZE) \
56     {                            \
57         SIZE, SelMapping##SIZE   \
58     }
59 
60 DEF_SEL_MAPPING_TBL(8);
61 DEF_SEL_MAPPING_TBL(16);
62 DEF_SEL_MAPPING_TBL(32);
63 DEF_SEL_MAPPING_TBL(64);
64 
65 std::map<uint32, std::function<MOperator(bool, uint32, uint32)>> fastIselMappingTable = {
66     USE_SELMAPPING_TBL(8), USE_SELMAPPING_TBL(16), USE_SELMAPPING_TBL(32), USE_SELMAPPING_TBL(64)};
67 
GetFastIselMop(Operand::OperandType dTy, Operand::OperandType sTy, PrimType type)68 MOperator GetFastIselMop(Operand::OperandType dTy, Operand::OperandType sTy, PrimType type)
69 {
70     uint32 bitSize = GetPrimTypeBitSize(type);
71     bool isInteger = IsPrimitiveInteger(type);
72     auto tableDriven = fastIselMappingTable.find(bitSize);
73     if (tableDriven != fastIselMappingTable.end()) {
74         auto funcIt = tableDriven->second;
75         return funcIt(isInteger, dTy, sTy);
76     } else {
77         CHECK_FATAL(false, "unsupport type");
78     }
79     return abstract::MOP_undef;
80 }
81 
82 #define DEF_EXTEND_MAPPING_TBL(TYPE) \
83     [](bool isSigned) -> MOperator { return isSigned ? abstract::MOP_sext_rr_##TYPE : abstract::MOP_zext_rr_##TYPE; }
84 using fromToTy = std::pair<uint32, uint32>; /* std::pair<from, to> */
85 #define DEF_USE_EXTEND_MAPPING_TBL(FROMSIZE, TOSIZE)                                            \
86     {                                                                                           \
87         {k##FROMSIZE##BitSize, k##TOSIZE##BitSize}, DEF_EXTEND_MAPPING_TBL(TOSIZE##_##FROMSIZE) \
88     }
89 
90 std::map<fromToTy, std::function<MOperator(bool)>> fastCvtMappingTableI = {
91     DEF_USE_EXTEND_MAPPING_TBL(8, 16), /* Extend Mapping */
92     DEF_USE_EXTEND_MAPPING_TBL(8, 32),  DEF_USE_EXTEND_MAPPING_TBL(8, 64),  DEF_USE_EXTEND_MAPPING_TBL(16, 32),
93     DEF_USE_EXTEND_MAPPING_TBL(16, 64), DEF_USE_EXTEND_MAPPING_TBL(32, 64),
94 };
95 #undef DEF_USE_EXTEND_MAPPING_TBL
96 #undef DEF_EXTEND_MAPPING_TBL
97 
GetFastCvtMopI(uint32 fromSize, uint32 toSize, bool isSigned)98 static MOperator GetFastCvtMopI(uint32 fromSize, uint32 toSize, bool isSigned)
99 {
100     if (toSize < k8BitSize || toSize > k64BitSize) {
101         CHECK_FATAL(false, "unsupport type");
102     }
103     if (fromSize < k8BitSize || fromSize > k64BitSize) {
104         CHECK_FATAL(false, "unsupport type");
105     }
106     /* Extend: fromSize < toSize */
107     auto tableDriven = fastCvtMappingTableI.find({fromSize, toSize});
108     if (tableDriven == fastCvtMappingTableI.end()) {
109         CHECK_FATAL(false, "unsupport cvt");
110     }
111     MOperator mOp = tableDriven->second(isSigned);
112     if (mOp == abstract::MOP_undef) {
113         CHECK_FATAL(false, "unsupport cvt");
114     }
115     return mOp;
116 }
117 
118 /*
119  * fast get MOperator
120  * such as : and, or, shl ...
121  */
122 #define DEF_MOPERATOR_MAPPING_FUNC(TYPE)                                                           \
123     [](uint32 bitSize)->MOperator {                                                              \
124         /* 8-bits,                16-bits,                   32-bits,                   64-bits */ \
125         constexpr static std::array<MOperator, kBitIndexEnd> fastMapping_##TYPE = {                \
126             abstract::MOP_##TYPE##_8, abstract::MOP_##TYPE##_16, abstract::MOP_##TYPE##_32,        \
127             abstract::MOP_##TYPE##_64};                                                            \
128         return fastMapping_##TYPE[GetBitIndex(bitSize)];                                           \
129     }
130 
131 #define DEF_FLOAT_MOPERATOR_MAPPING_FUNC(TYPE)                                                     \
132     [](uint32 bitSize)->MOperator {                                                              \
133         /* 8-bits,                16-bits,                   32-bits,                   64-bits */ \
134         constexpr static std::array<MOperator, kBitIndexEnd> fastMapping_f_##TYPE = {              \
135             abstract::MOP_##TYPE##_f_8, abstract::MOP_##TYPE##_f_16, abstract::MOP_##TYPE##_f_32,  \
136             abstract::MOP_##TYPE##_f_64};                                                          \
137         return fastMapping_f_##TYPE[GetBitIndex(bitSize)];                                         \
138     }
139 
HandleDassign(StmtNode &stmt, MPISel &iSel)140 static void HandleDassign(StmtNode &stmt, MPISel &iSel)
141 {
142     DEBUG_ASSERT(stmt.GetOpCode() == OP_dassign, "expect dassign");
143     auto &dassignNode = static_cast<DassignNode &>(stmt);
144     BaseNode *rhs = dassignNode.GetRHS();
145     DEBUG_ASSERT(rhs != nullptr, "get rhs of dassignNode failed");
146     Operand *opndRhs = iSel.HandleExpr(dassignNode, *rhs);
147     if (opndRhs == nullptr) {
148         return;
149     }
150     iSel.SelectDassign(dassignNode, *opndRhs);
151 }
152 
HandleIassign(StmtNode &stmt, MPISel &iSel)153 static void HandleIassign(StmtNode &stmt, MPISel &iSel)
154 {
155     DEBUG_ASSERT(stmt.GetOpCode() == OP_iassign, "expect iassign");
156     auto &iassignNode = static_cast<IassignNode &>(stmt);
157     BaseNode *rhs = iassignNode.GetRHS();
158     DEBUG_ASSERT(rhs != nullptr, "null ptr check");
159     Operand *opndRhs = iSel.HandleExpr(stmt, *rhs);
160     BaseNode *addr = iassignNode.Opnd(0);
161     DEBUG_ASSERT(addr != nullptr, "null ptr check");
162     Operand *opndAddr = iSel.HandleExpr(stmt, *addr);
163     if (opndRhs == nullptr || opndAddr == nullptr) {
164         return;
165     }
166     iSel.SelectIassign(iassignNode, *opndAddr, *opndRhs);
167 }
168 
HandleRegassign(StmtNode &stmt, MPISel &iSel)169 static void HandleRegassign(StmtNode &stmt, MPISel &iSel)
170 {
171     DEBUG_ASSERT(stmt.GetOpCode() == OP_regassign, "expect regAssign");
172     auto &regAssignNode = static_cast<RegassignNode &>(stmt);
173     BaseNode *operand = regAssignNode.Opnd(0);
174     DEBUG_ASSERT(operand != nullptr, "get operand of regassignNode failed");
175     Operand *opnd0 = iSel.HandleExpr(regAssignNode, *operand);
176     iSel.SelectRegassign(regAssignNode, *opnd0);
177 }
178 
HandleLabel(StmtNode &stmt, const MPISel &iSel)179 static void HandleLabel(StmtNode &stmt, const MPISel &iSel)
180 {
181     CGFunc *cgFunc = iSel.GetCurFunc();
182     DEBUG_ASSERT(stmt.GetOpCode() == OP_label, "error");
183     auto &label = static_cast<LabelNode &>(stmt);
184     BB *newBB = cgFunc->StartNewBBImpl(false, label);
185     newBB->AddLabel(label.GetLabelIdx());
186     cgFunc->SetLab2BBMap(static_cast<int32>(newBB->GetLabIdx()), *newBB);
187     cgFunc->SetCurBB(*newBB);
188 }
189 
HandleGoto(StmtNode &stmt, MPISel &iSel)190 static void HandleGoto(StmtNode &stmt, MPISel &iSel)
191 {
192     CGFunc *cgFunc = iSel.GetCurFunc();
193     auto &gotoNode = static_cast<GotoNode &>(stmt);
194     DEBUG_ASSERT(gotoNode.GetOpCode() == OP_goto, "expect goto");
195     cgFunc->SetCurBBKind(BB::kBBGoto);
196     iSel.SelectGoto(gotoNode);
197     cgFunc->SetCurBB(*cgFunc->StartNewBB(gotoNode));
198     DEBUG_ASSERT(&stmt == &gotoNode, "stmt must be same as gotoNoe");
199     if ((gotoNode.GetNext() != nullptr) && (gotoNode.GetNext()->GetOpCode() != OP_label)) {
200         DEBUG_ASSERT(cgFunc->GetCurBB()->GetPrev()->GetLastStmt() == &stmt, "check the relation between BB and stmt");
201     }
202 }
203 
HandleIntrinCall(StmtNode &stmt, MPISel &iSel)204 static void HandleIntrinCall(StmtNode &stmt, MPISel &iSel)
205 {
206     auto &call = static_cast<IntrinsiccallNode &>(stmt);
207     iSel.SelectIntrinsicCall(call);
208 }
209 
HandleRangeGoto(StmtNode &stmt, MPISel &iSel)210 static void HandleRangeGoto(StmtNode &stmt, MPISel &iSel)
211 {
212     CGFunc *cgFunc = iSel.GetCurFunc();
213     auto &rangeGotoNode = static_cast<RangeGotoNode &>(stmt);
214     DEBUG_ASSERT(rangeGotoNode.GetOpCode() == OP_rangegoto, "expect rangegoto");
215     BaseNode *srcNode = rangeGotoNode.Opnd(0);
216     Operand *srcOpnd = iSel.HandleExpr(rangeGotoNode, *srcNode);
217     cgFunc->SetCurBBKind(BB::kBBRangeGoto);
218     iSel.SelectRangeGoto(rangeGotoNode, *srcOpnd);
219 }
220 
HandleReturn(StmtNode &stmt, MPISel &iSel)221 void HandleReturn(StmtNode &stmt, MPISel &iSel)
222 {
223     CGFunc *cgFunc = iSel.GetCurFunc();
224     auto &retNode = static_cast<NaryStmtNode &>(stmt);
225     DEBUG_ASSERT(retNode.NumOpnds() <= 1, "NYI return nodes number > 1");
226     if (retNode.NumOpnds() != 0) {
227         Operand *opnd = iSel.HandleExpr(retNode, *retNode.Opnd(0));
228         iSel.SelectReturn(retNode, *opnd);
229     }
230     iSel.SelectReturn();
231     /* return stmt will jump to the ret BB, so curBB is gotoBB */
232     cgFunc->SetCurBBKind(BB::kBBGoto);
233     cgFunc->SetCurBB(*cgFunc->StartNewBB(retNode));
234 }
235 
HandleComment(StmtNode &stmt, MPISel &iSel)236 static void HandleComment(StmtNode &stmt, MPISel &iSel)
237 {
238     return;
239 }
240 
HandleIcall(StmtNode &stmt, MPISel &iSel)241 static void HandleIcall(StmtNode &stmt, MPISel &iSel)
242 {
243     DEBUG_ASSERT(stmt.GetOpCode() == OP_icall || stmt.GetOpCode() == OP_icallproto, "error");
244     auto &iCallNode = static_cast<IcallNode &>(stmt);
245     iSel.SelectIcall(iCallNode);
246     iSel.SelectCallCommon(stmt, iSel);
247 }
248 
HandleCall(StmtNode &stmt, MPISel &iSel)249 static void HandleCall(StmtNode &stmt, MPISel &iSel)
250 {
251     DEBUG_ASSERT(stmt.GetOpCode() == OP_call, "error");
252     auto &callNode = static_cast<CallNode &>(stmt);
253     iSel.SelectCall(callNode);
254     iSel.SelectCallCommon(stmt, iSel);
255 }
256 
HandleCondbr(StmtNode &stmt, MPISel &iSel)257 static void HandleCondbr(StmtNode &stmt, MPISel &iSel)
258 {
259     CGFunc *cgFunc = iSel.GetCurFunc();
260     auto &condGotoNode = static_cast<CondGotoNode &>(stmt);
261     BaseNode *condNode = condGotoNode.Opnd(0);
262     DEBUG_ASSERT(condNode != nullptr, "expect first operand of cond br");
263     /* select cmpOp Insn and get the result "opnd0". However, the opnd0 is not used
264      * in most backend architectures */
265     Operand *opnd0 = iSel.HandleExpr(stmt, *condNode);
266     iSel.SelectCondGoto(condGotoNode, *condNode, *opnd0);
267     cgFunc->SetCurBB(*cgFunc->StartNewBB(condGotoNode));
268 }
269 
HandleShift(const BaseNode &parent, BaseNode &expr, MPISel &iSel)270 static Operand *HandleShift(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
271 {
272     return iSel.SelectShift(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
273                             *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
274 }
275 
HandleCvt(const BaseNode &parent, BaseNode &expr, MPISel &iSel)276 static Operand *HandleCvt(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
277 {
278     return iSel.SelectCvt(parent, static_cast<TypeCvtNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)));
279 }
280 
HandleExtractBits(const BaseNode &parent, BaseNode &expr, MPISel &iSel)281 static Operand *HandleExtractBits(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
282 {
283     return iSel.SelectExtractbits(parent, static_cast<ExtractbitsNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)));
284 }
285 
HandleDread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)286 static Operand *HandleDread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
287 {
288     auto &dreadNode = static_cast<AddrofNode &>(expr);
289     return iSel.SelectDread(parent, dreadNode);
290 }
291 
HandleAdd(const BaseNode &parent, BaseNode &expr, MPISel &iSel)292 static Operand *HandleAdd(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
293 {
294     return iSel.SelectAdd(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
295                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
296 }
297 
HandleBior(const BaseNode &parent, BaseNode &expr, MPISel &iSel)298 static Operand *HandleBior(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
299 {
300     return iSel.SelectBior(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
301                            *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
302 }
303 
HandleBxor(const BaseNode &parent, BaseNode &expr, MPISel &iSel)304 static Operand *HandleBxor(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
305 {
306     DEBUG_ASSERT(expr.Opnd(1) != nullptr, "nullptr check");
307     return iSel.SelectBxor(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
308                            *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
309 }
310 
HandleSub(const BaseNode &parent, BaseNode &expr, MPISel &iSel)311 static Operand *HandleSub(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
312 {
313     return iSel.SelectSub(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
314                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
315 }
316 
HandleDiv(const BaseNode &parent, BaseNode &expr, MPISel &iSel)317 static Operand *HandleDiv(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
318 {
319     return iSel.SelectDiv(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
320                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
321 }
322 
HandleRem(const BaseNode &parent, BaseNode &expr, MPISel &iSel)323 static Operand *HandleRem(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
324 {
325     return iSel.SelectRem(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
326                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
327 }
328 
HandleBand(const BaseNode &parent, BaseNode &expr, MPISel &iSel)329 static Operand *HandleBand(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
330 {
331     return iSel.SelectBand(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
332                            *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
333 }
334 
HandleMpy(const BaseNode &parent, BaseNode &expr, MPISel &iSel)335 static Operand *HandleMpy(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
336 {
337     return iSel.SelectMpy(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
338                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
339 }
340 
HandleTrunc(const BaseNode &parent, BaseNode &expr, MPISel &iSel)341 static Operand *HandleTrunc(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
342 {
343     DEBUG_ASSERT(expr.Opnd(0) != nullptr, "null ptr check");
344     return iSel.SelectCvt(parent, static_cast<TypeCvtNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)));
345 }
346 
HandleConstVal(const BaseNode &parent, BaseNode &expr, MPISel &iSel)347 static Operand *HandleConstVal(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
348 {
349     auto &constValNode = static_cast<ConstvalNode &>(expr);
350     MIRConst *mirConst = constValNode.GetConstVal();
351     DEBUG_ASSERT(mirConst != nullptr, "get constval of constvalnode failed");
352     if (mirConst->GetKind() == kConstInt) {
353         auto *mirIntConst = safe_cast<MIRIntConst>(mirConst);
354         return iSel.SelectIntConst(*mirIntConst, constValNode.GetPrimType());
355     } else if (mirConst->GetKind() == kConstDoubleConst) {
356         auto *mirDoubleConst = safe_cast<MIRDoubleConst>(mirConst);
357         return iSel.SelectFloatingConst(*mirDoubleConst, constValNode.GetPrimType());
358     } else if (mirConst->GetKind() == kConstFloatConst) {
359         auto *mirFloatConst = safe_cast<MIRFloatConst>(mirConst);
360         DEBUG_ASSERT(mirFloatConst != nullptr, "nullptr check");
361         return iSel.SelectFloatingConst(*mirFloatConst, constValNode.GetPrimType());
362     } else {
363         CHECK_FATAL(false, "NIY");
364     }
365     return nullptr;
366 }
367 
HandleRegread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)368 static Operand *HandleRegread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
369 {
370     (void)parent;
371     auto &regReadNode = static_cast<RegreadNode &>(expr);
372     /* handle return Val */
373     if (regReadNode.GetRegIdx() == -kSregRetval0 || regReadNode.GetRegIdx() == -kSregRetval1) {
374         return &iSel.ProcessReturnReg(regReadNode.GetPrimType(), -(regReadNode.GetRegIdx()));
375     }
376     return iSel.SelectRegread(regReadNode);
377 }
378 
HandleIread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)379 static Operand *HandleIread(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
380 {
381     auto &ireadNode = static_cast<IreadNode &>(expr);
382     return iSel.SelectIread(parent, ireadNode);
383 }
384 
HandleBnot(const BaseNode &parent, BaseNode &expr, MPISel &iSel)385 static Operand *HandleBnot(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
386 {
387     return iSel.SelectBnot(static_cast<UnaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)), parent);
388 }
389 
HandleLnot(const BaseNode &parent, BaseNode &expr, MPISel &iSel)390 static Operand *HandleLnot(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
391 {
392     return iSel.SelectLnot(static_cast<UnaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)), parent);
393 }
394 
HandleCmp(const BaseNode &parent, BaseNode &expr, MPISel &iSel)395 static Operand *HandleCmp(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
396 {
397     // fix opnd type before select insn
398     PrimType targetPtyp = parent.GetPrimType();
399     if (kOpcodeInfo.IsCompare(parent.GetOpCode())) {
400         targetPtyp = static_cast<const CompareNode &>(parent).GetOpndType();
401     } else if (kOpcodeInfo.IsTypeCvt(parent.GetOpCode())) {
402         targetPtyp = static_cast<const TypeCvtNode &>(parent).FromType();
403     }
404     if ((IsPrimitiveInteger(targetPtyp) || IsPrimitiveFloat(targetPtyp)) && targetPtyp != expr.GetPrimType()) {
405         expr.SetPrimType(targetPtyp);
406     }
407     return iSel.SelectCmpOp(static_cast<CompareNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
408                             *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
409 }
410 
HandleAbs(const BaseNode &parent, BaseNode &expr, MPISel &iSel)411 static Operand *HandleAbs(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
412 {
413     return iSel.SelectAbs(static_cast<UnaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)));
414 }
415 
HandleMin(const BaseNode &parent, BaseNode &expr, MPISel &iSel)416 static Operand *HandleMin(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
417 {
418     return iSel.SelectMin(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
419                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
420 }
421 
HandleMax(const BaseNode &parent, BaseNode &expr, MPISel &iSel)422 static Operand *HandleMax(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
423 {
424     return iSel.SelectMax(static_cast<BinaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)),
425                           *iSel.HandleExpr(expr, *expr.Opnd(1)), parent);
426 }
HandleRetype(const BaseNode &parent, BaseNode &expr, MPISel &iSel)427 static Operand *HandleRetype(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
428 {
429     DEBUG_ASSERT(expr.Opnd(0) != nullptr, "expr.Opnd(0) should not be nullptr");
430     return iSel.SelectRetype(static_cast<TypeCvtNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)));
431 }
432 
HandleIntrinOp(const BaseNode &parent, BaseNode &expr, MPISel &iSel)433 static Operand *HandleIntrinOp(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
434 {
435     auto &intrinsicopNode = static_cast<IntrinsicopNode &>(expr);
436     switch (intrinsicopNode.GetIntrinsic()) {
437         case INTRN_C_clz32:
438         case INTRN_C_clz64:
439             return iSel.SelectCclz(intrinsicopNode, *iSel.HandleExpr(expr, *expr.Opnd(0)), parent);
440         default:
441             DEBUG_ASSERT(false, "NIY, unsupported intrinsicop.");
442             return nullptr;
443     }
444 }
445 
HandleSqrt(const BaseNode &parent, BaseNode &expr, MPISel &iSel)446 static Operand *HandleSqrt(const BaseNode &parent, BaseNode &expr, MPISel &iSel)
447 {
448     DEBUG_ASSERT(expr.Opnd(0) != nullptr, "expr.Opnd(0) should not be nullptr");
449     return iSel.SelectSqrt(static_cast<UnaryNode &>(expr), *iSel.HandleExpr(expr, *expr.Opnd(0)), parent);
450 }
451 
452 using HandleStmtFactory = FunctionFactory<Opcode, void, StmtNode &, MPISel &>;
453 using HandleExprFactory = FunctionFactory<Opcode, maplebe::Operand *, const BaseNode &, BaseNode &, MPISel &>;
454 namespace isel {
InitHandleStmtFactory()455 static void InitHandleStmtFactory()
456 {
457     RegisterFactoryFunction<HandleStmtFactory>(OP_label, HandleLabel);
458     RegisterFactoryFunction<HandleStmtFactory>(OP_dassign, HandleDassign);
459     RegisterFactoryFunction<HandleStmtFactory>(OP_iassign, HandleIassign);
460     RegisterFactoryFunction<HandleStmtFactory>(OP_regassign, HandleRegassign);
461     RegisterFactoryFunction<HandleStmtFactory>(OP_return, HandleReturn);
462     RegisterFactoryFunction<HandleStmtFactory>(OP_comment, HandleComment);
463     RegisterFactoryFunction<HandleStmtFactory>(OP_call, HandleCall);
464     RegisterFactoryFunction<HandleStmtFactory>(OP_icall, HandleIcall);
465     RegisterFactoryFunction<HandleStmtFactory>(OP_icallproto, HandleIcall);
466     RegisterFactoryFunction<HandleStmtFactory>(OP_goto, HandleGoto);
467     RegisterFactoryFunction<HandleStmtFactory>(OP_intrinsiccall, HandleIntrinCall);
468     RegisterFactoryFunction<HandleStmtFactory>(OP_intrinsiccallassigned, HandleIntrinCall);
469     RegisterFactoryFunction<HandleStmtFactory>(OP_rangegoto, HandleRangeGoto);
470     RegisterFactoryFunction<HandleStmtFactory>(OP_brfalse, HandleCondbr);
471     RegisterFactoryFunction<HandleStmtFactory>(OP_brtrue, HandleCondbr);
472 }
InitHandleExprFactory()473 static void InitHandleExprFactory()
474 {
475     RegisterFactoryFunction<HandleExprFactory>(OP_dread, HandleDread);
476     RegisterFactoryFunction<HandleExprFactory>(OP_add, HandleAdd);
477     RegisterFactoryFunction<HandleExprFactory>(OP_sub, HandleSub);
478     RegisterFactoryFunction<HandleExprFactory>(OP_mul, HandleMpy);
479     RegisterFactoryFunction<HandleExprFactory>(OP_constval, HandleConstVal);
480     RegisterFactoryFunction<HandleExprFactory>(OP_regread, HandleRegread);
481     RegisterFactoryFunction<HandleExprFactory>(OP_shl, HandleShift);
482     RegisterFactoryFunction<HandleExprFactory>(OP_lshr, HandleShift);
483     RegisterFactoryFunction<HandleExprFactory>(OP_ashr, HandleShift);
484     RegisterFactoryFunction<HandleExprFactory>(OP_cvt, HandleCvt);
485     RegisterFactoryFunction<HandleExprFactory>(OP_zext, HandleExtractBits);
486     RegisterFactoryFunction<HandleExprFactory>(OP_sext, HandleExtractBits);
487     RegisterFactoryFunction<HandleExprFactory>(OP_band, HandleBand);
488     RegisterFactoryFunction<HandleExprFactory>(OP_bior, HandleBior);
489     RegisterFactoryFunction<HandleExprFactory>(OP_bxor, HandleBxor);
490     RegisterFactoryFunction<HandleExprFactory>(OP_iread, HandleIread);
491     RegisterFactoryFunction<HandleExprFactory>(OP_bnot, HandleBnot);
492     RegisterFactoryFunction<HandleExprFactory>(OP_lnot, HandleLnot);
493     RegisterFactoryFunction<HandleExprFactory>(OP_div, HandleDiv);
494     RegisterFactoryFunction<HandleExprFactory>(OP_rem, HandleRem);
495     RegisterFactoryFunction<HandleExprFactory>(OP_le, HandleCmp);
496     RegisterFactoryFunction<HandleExprFactory>(OP_ge, HandleCmp);
497     RegisterFactoryFunction<HandleExprFactory>(OP_gt, HandleCmp);
498     RegisterFactoryFunction<HandleExprFactory>(OP_lt, HandleCmp);
499     RegisterFactoryFunction<HandleExprFactory>(OP_ne, HandleCmp);
500     RegisterFactoryFunction<HandleExprFactory>(OP_eq, HandleCmp);
501     RegisterFactoryFunction<HandleExprFactory>(OP_abs, HandleAbs);
502     RegisterFactoryFunction<HandleExprFactory>(OP_min, HandleMin);
503     RegisterFactoryFunction<HandleExprFactory>(OP_max, HandleMax);
504     RegisterFactoryFunction<HandleExprFactory>(OP_retype, HandleRetype);
505     RegisterFactoryFunction<HandleExprFactory>(OP_trunc, HandleTrunc);
506     RegisterFactoryFunction<HandleExprFactory>(OP_intrinsicop, HandleIntrinOp);
507     RegisterFactoryFunction<HandleExprFactory>(OP_sqrt, HandleSqrt);
508 }
509 }  // namespace isel
510 
HandleExpr(const BaseNode &parent, BaseNode &expr)511 Operand *MPISel::HandleExpr(const BaseNode &parent, BaseNode &expr)
512 {
513     auto function = CreateProductFunction<HandleExprFactory>(expr.GetOpCode());
514     CHECK_FATAL(function != nullptr, "unsupported %d opCode in HandleExpr()", expr.GetOpCode());
515     Operand *opnd = function(parent, expr, *this);
516     return opnd;
517 }
518 
doMPIS()519 void MPISel::doMPIS()
520 {
521     isel::InitHandleStmtFactory();
522     isel::InitHandleExprFactory();
523     StmtNode *secondStmt = HandleFuncEntry();
524     for (StmtNode *stmt = secondStmt; stmt != nullptr; stmt = stmt->GetNext()) {
525         auto function = CreateProductFunction<HandleStmtFactory>(stmt->GetOpCode());
526         CHECK_FATAL(function != nullptr, "unsupported opCode or has been lowered before");
527         cgFunc->GetInsnBuilder()->SetDebugComment(stmt->GetDebugComment());
528         function(*stmt, *this);
529         cgFunc->GetInsnBuilder()->ClearDebugComment();
530     }
531     HandleFuncExit();
532 }
533 
GetIntegerPrimTypeFromSize(bool isSigned, uint32 bitSize)534 PrimType MPISel::GetIntegerPrimTypeFromSize(bool isSigned, uint32 bitSize)
535 {
536     static constexpr std::array<PrimType, kBitIndexEnd> signedPrimType = {PTY_i8, PTY_i16, PTY_i32, PTY_i64};
537     static constexpr std::array<PrimType, kBitIndexEnd> unsignedPrimType = {PTY_u8, PTY_u16, PTY_u32, PTY_u64};
538     BitIndex index = GetBitIndex(bitSize);
539     return isSigned ? signedPrimType[index] : unsignedPrimType[index];
540 }
541 
SelectCallCommon(StmtNode &stmt, const MPISel &iSel)542 void MPISel::SelectCallCommon(StmtNode &stmt, const MPISel &iSel)
543 {
544     CGFunc *cgFunc = iSel.GetCurFunc();
545     if (cgFunc->GetCurBB()->GetKind() != BB::kBBFallthru) {
546         cgFunc->SetCurBB(*cgFunc->StartNewBB(stmt));
547     }
548 }
549 
SelectBasicOp(Operand &resOpnd, Operand &opnd0, Operand &opnd1, MOperator mOp, PrimType primType)550 void MPISel::SelectBasicOp(Operand &resOpnd, Operand &opnd0, Operand &opnd1, MOperator mOp, PrimType primType)
551 {
552     RegOperand &firstOpnd = SelectCopy2Reg(opnd0, primType);
553     RegOperand &secondOpnd = SelectCopy2Reg(opnd1, primType);
554     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
555     (void)insn.AddOpndChain(resOpnd).AddOpndChain(firstOpnd).AddOpndChain(secondOpnd);
556     cgFunc->GetCurBB()->AppendInsn(insn);
557 }
558 
GetFieldIdAndMirTypeFromMirNode(const BaseNode &node)559 std::pair<FieldID, MIRType *> MPISel::GetFieldIdAndMirTypeFromMirNode(const BaseNode &node)
560 {
561     FieldID fieldId = 0;
562     MIRType *mirType = nullptr;
563     if (node.GetOpCode() == maple::OP_iread) {
564         /* mirType stored in an addr. */
565         auto &iread = static_cast<const IreadNode &>(node);
566         fieldId = iread.GetFieldID();
567         MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread.GetTyIdx());
568         MIRPtrType *pointerType = static_cast<MIRPtrType *>(type);
569         DEBUG_ASSERT(pointerType != nullptr, "expect a pointer type at iread node");
570         mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx());
571         if (mirType->GetKind() == kTypeArray) {
572             MIRArrayType *arrayType = static_cast<MIRArrayType *>(mirType);
573             mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(arrayType->GetElemTyIdx());
574         }
575     } else if (node.GetOpCode() == maple::OP_dassign) {
576         /* mirSymbol */
577         auto &dassign = static_cast<const DassignNode &>(node);
578         fieldId = dassign.GetFieldID();
579         MIRSymbol *symbol = cgFunc->GetFunction().GetLocalOrGlobalSymbol(dassign.GetStIdx());
580         mirType = symbol->GetType();
581     } else if (node.GetOpCode() == maple::OP_dread) {
582         /* mirSymbol */
583         auto &dread = static_cast<const AddrofNode &>(node);
584         fieldId = dread.GetFieldID();
585         MIRSymbol *symbol = cgFunc->GetFunction().GetLocalOrGlobalSymbol(dread.GetStIdx());
586         mirType = symbol->GetType();
587     } else if (node.GetOpCode() == maple::OP_iassign) {
588         auto &iassign = static_cast<const IassignNode &>(node);
589         fieldId = iassign.GetFieldID();
590         MIRType *iassignMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iassign.GetTyIdx());
591         MIRPtrType *pointerType = nullptr;
592         DEBUG_ASSERT(iassignMirType->GetKind() == kTypePointer, "non-pointer");
593         pointerType = static_cast<MIRPtrType *>(iassignMirType);
594         mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerType->GetPointedTyIdx());
595     } else {
596         CHECK_FATAL(false, "unsupported OpCode");
597     }
598     return {fieldId, mirType};
599 }
600 
GetMirTypeInfoFormFieldIdAndMirType(FieldID fieldId, MIRType *mirType)601 MirTypeInfo MPISel::GetMirTypeInfoFormFieldIdAndMirType(FieldID fieldId, MIRType *mirType)
602 {
603     MirTypeInfo mirTypeInfo;
604     /* fixup primType and offset */
605     mirTypeInfo.primType = mirType->GetPrimType();
606     return mirTypeInfo;
607 }
608 
GetMirTypeInfoFromMirNode(const BaseNode &node)609 MirTypeInfo MPISel::GetMirTypeInfoFromMirNode(const BaseNode &node)
610 {
611     auto [fieldId, mirType] = GetFieldIdAndMirTypeFromMirNode(node);
612     return GetMirTypeInfoFormFieldIdAndMirType(fieldId, mirType);
613 }
614 
SelectDassign(const DassignNode &stmt, Operand &opndRhs)615 void MPISel::SelectDassign(const DassignNode &stmt, Operand &opndRhs)
616 {
617     /* mirSymbol info */
618     MIRSymbol *symbol = cgFunc->GetFunction().GetLocalOrGlobalSymbol(stmt.GetStIdx());
619     MirTypeInfo symbolInfo = GetMirTypeInfoFromMirNode(stmt);
620     /* Get symbol location */
621     DEBUG_ASSERT(symbol != nullptr, "nullptr check");
622     MemOperand &symbolMem = GetOrCreateMemOpndFromSymbol(*symbol, stmt.GetFieldID());
623     /* rhs mirType info */
624     PrimType rhsType = stmt.GetRHS()->GetPrimType();
625     /* Generate Insn */
626     PrimType memType = symbolInfo.primType;
627     SelectCopy(symbolMem, opndRhs, memType, rhsType);
628     if (rhsType == PTY_ref) {
629         cgFunc->AddReferenceStackSlot(symbolMem.GetOffsetImmediate()->GetOffsetValue());
630     }
631 
632     return;
633 }
634 
SelectIassign(const IassignNode &stmt, Operand &opndAddr, Operand &opndRhs)635 void MPISel::SelectIassign(const IassignNode &stmt, Operand &opndAddr, Operand &opndRhs)
636 {
637     /* mirSymbol info */
638     MirTypeInfo symbolInfo = GetMirTypeInfoFromMirNode(stmt);
639     /* handle Lhs, generate (%Rxx) via Rxx*/
640     PrimType memType = symbolInfo.primType;
641     RegOperand &lhsBaseOpnd = SelectCopy2Reg(opndAddr, stmt.Opnd(0)->GetPrimType());
642     MemOperand &lhsMemOpnd =
643         cgFunc->GetOpndBuilder()->CreateMem(lhsBaseOpnd, symbolInfo.offset, GetPrimTypeBitSize(memType));
644     /* handle Rhs, get R## from Rhs */
645     PrimType rhsType = stmt.GetRHS()->GetPrimType();
646     /* mov %R##, (%Rxx) */
647     SelectCopy(lhsMemOpnd, opndRhs, memType, rhsType);
648 }
649 
SelectIntConst(const MIRIntConst &intConst, PrimType primType)650 ImmOperand *MPISel::SelectIntConst(const MIRIntConst &intConst, PrimType primType)
651 {
652     return &cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(primType), intConst.GetExtValue());
653 }
654 
SelectShift(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)655 Operand *MPISel::SelectShift(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
656 {
657     PrimType primType = node.GetPrimType();
658     RegOperand *resOpnd = nullptr;
659     Opcode opcode = node.GetOpCode();
660 
661     if (IsPrimitiveInteger(primType)) {
662         resOpnd =
663             &(cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType)));
664         RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
665         SelectShift(*resOpnd, regOpnd0, opnd1, opcode, primType, node.Opnd(1)->GetPrimType());
666     } else {
667         CHECK_FATAL(false, "NIY vector cvt");
668     }
669     return resOpnd;
670 }
671 
SelectShift(Operand &resOpnd, Operand &opnd0, Operand &opnd1, Opcode shiftDirect, PrimType opnd0Type, PrimType opnd1Type)672 void MPISel::SelectShift(Operand &resOpnd, Operand &opnd0, Operand &opnd1, Opcode shiftDirect, PrimType opnd0Type,
673                          PrimType opnd1Type)
674 {
675     if (opnd1.IsIntImmediate() && static_cast<ImmOperand &>(opnd1).GetValue() == 0) {
676         SelectCopy(resOpnd, opnd0, opnd0Type);
677         return;
678     }
679 
680     uint32 dsize = GetPrimTypeBitSize(opnd0Type);
681     MOperator mOp = abstract::MOP_undef;
682     if (shiftDirect == OP_shl) {
683         const static auto fastShlMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(shl);
684         mOp = fastShlMappingFunc(dsize);
685     } else if (shiftDirect == OP_ashr) {
686         const static auto fastAshrMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(ashr);
687         mOp = fastAshrMappingFunc(dsize);
688     } else if (shiftDirect == OP_lshr) {
689         const static auto fastLshrMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(lshr);
690         mOp = fastLshrMappingFunc(dsize);
691     } else {
692         CHECK_FATAL(false, "NIY, Not support shiftdirect case");
693     }
694     RegOperand &firstOpnd = SelectCopy2Reg(opnd0, opnd0Type);
695     RegOperand &secondOpnd = SelectCopy2Reg(opnd1, opnd1Type);
696     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
697     insn.AddOpndChain(resOpnd).AddOpndChain(firstOpnd).AddOpndChain(secondOpnd);
698     cgFunc->GetCurBB()->AppendInsn(insn);
699 }
700 
SelectRegassign(RegassignNode &stmt, Operand &opnd0)701 void MPISel::SelectRegassign(RegassignNode &stmt, Operand &opnd0)
702 {
703     PrimType rhsType = stmt.Opnd(0)->GetPrimType();
704     PregIdx pregIdx = stmt.GetRegIdx();
705     PrimType regType = stmt.GetPrimType();
706     RegOperand &regOpnd =
707         cgFunc->GetOpndBuilder()->CreateVReg(cgFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx),
708                                              GetPrimTypeBitSize(regType), cgFunc->GetRegTyFromPrimTy(regType));
709     SelectCopy(regOpnd, opnd0, regType, rhsType);
710     if (stmt.GetPrimType() == PTY_ref) {
711         regOpnd.SetIsReference(true);
712         cgFunc->AddReferenceReg(regOpnd.GetRegisterNumber());
713     }
714     if (pregIdx > 0) {
715         // special MIRPreg is not supported
716         cgFunc->SetPregIdx2Opnd(pregIdx, regOpnd);
717     }
718     const auto &derived2BaseRef = cgFunc->GetFunction().GetDerived2BaseRef();
719     auto itr = derived2BaseRef.find(pregIdx);
720     if (itr != derived2BaseRef.end()) {
721         auto *opnd = cgFunc->GetOpndFromPregIdx(itr->first);
722         CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
723         auto &derivedRegOpnd = static_cast<RegOperand &>(*opnd);
724         opnd = cgFunc->GetOpndFromPregIdx(itr->second);
725         CHECK_FATAL(opnd != nullptr, "pregIdx has not been assigned Operand");
726         auto &baseRegOpnd = static_cast<RegOperand &>(*opnd);
727         derivedRegOpnd.SetBaseRefOpnd(baseRegOpnd);
728     }
729     if ((Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) && (pregIdx >= 0)) {
730         const SymbolAlloc *symLoc = cgFunc->GetMemlayout()->GetSpillLocOfPseduoRegister(pregIdx);
731         int64 offset = static_cast<int64>(cgFunc->GetBaseOffset(*symLoc));
732         MIRPreg *preg = cgFunc->GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
733         uint32 bitLen = GetPrimTypeSize(preg->GetPrimType()) * kBitsPerByte;
734         RegOperand &base = GetTargetBasicPointer(PTY_u64);
735         MemOperand *dest = &cgFunc->GetOpndBuilder()->CreateMem(base, offset, bitLen);
736         SelectCopy(*dest, regOpnd, preg->GetPrimType(), regType);
737     }
738 }
739 
SelectRegread(RegreadNode &expr)740 RegOperand *MPISel::SelectRegread(RegreadNode &expr)
741 {
742     PregIdx pregIdx = expr.GetRegIdx();
743     PrimType rhsType = expr.GetPrimType();
744     if (pregIdx < 0) {
745         return &SelectSpecialRegread(pregIdx, rhsType);
746     }
747 
748     RegOperand &reg = cgFunc->GetOpndBuilder()->CreateVReg(cgFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx),
749                                                            GetPrimTypeSize(rhsType) * kBitsPerByte,
750                                                            cgFunc->GetRegTyFromPrimTy(rhsType));
751     if (cgFunc->GetOpndFromPregIdx(pregIdx) == nullptr) {
752         cgFunc->SetPregIdx2Opnd(pregIdx, reg);
753     }
754     if (expr.GetPrimType() == maple::PTY_ref) {
755         reg.SetIsReference(true);
756         cgFunc->AddReferenceReg(reg.GetRegisterNumber());
757     }
758     if (Globals::GetInstance()->GetOptimLevel() == CGOptions::kLevel0) {
759         const SymbolAlloc *symLoc = cgFunc->GetMemlayout()->GetSpillLocOfPseduoRegister(pregIdx);
760         int64 offset = static_cast<int64>(cgFunc->GetBaseOffset(*symLoc));
761         MIRPreg *preg = cgFunc->GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
762         uint32 bitLen = GetPrimTypeSize(preg->GetPrimType()) * kBitsPerByte;
763         RegOperand &base = GetTargetBasicPointer(PTY_u64);
764         MemOperand *src = &cgFunc->GetOpndBuilder()->CreateMem(base, offset, bitLen);
765         SelectCopy(reg, *src, rhsType, preg->GetPrimType());
766     }
767     return &reg;
768 }
769 
SelectDread(const BaseNode &parent, const AddrofNode &expr)770 Operand *MPISel::SelectDread(const BaseNode &parent, const AddrofNode &expr)
771 {
772     /* get mirSymbol info*/
773     MIRSymbol *symbol = cgFunc->GetFunction().GetLocalOrGlobalSymbol(expr.GetStIdx());
774     MirTypeInfo symbolInfo = GetMirTypeInfoFromMirNode(expr);
775     PrimType symbolType = symbolInfo.primType;
776     /* Get symbol location */
777     MemOperand &symbolMem = GetOrCreateMemOpndFromSymbol(*symbol, expr.GetFieldID());
778     PrimType primType = expr.GetPrimType();
779     if (primType == PTY_ref) {
780         cgFunc->AddReferenceStackSlot(symbolMem.GetOffsetImmediate()->GetOffsetValue());
781     }
782 
783     /* for BasicType, load symbolVal to register. */
784     RegOperand &regOpnd =
785         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
786     if (primType == PTY_ref) {
787         regOpnd.SetIsReference(true);
788         cgFunc->AddReferenceReg(regOpnd.GetRegisterNumber());
789     }
790     /* Generate Insn */
791     SelectCopy(regOpnd, symbolMem, primType, symbolType);
792     return &regOpnd;
793 }
794 
SelectAdd(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)795 Operand *MPISel::SelectAdd(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
796 {
797     PrimType primType = node.GetPrimType();
798     RegOperand &resReg =
799         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
800     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
801     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
802     SelectAdd(resReg, regOpnd0, regOpnd1, primType);
803     return &resReg;
804 }
805 
SelectBand(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)806 Operand *MPISel::SelectBand(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
807 {
808     PrimType primType = node.GetPrimType();
809     RegOperand &resReg =
810         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
811     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
812     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
813     SelectBand(resReg, regOpnd0, regOpnd1, primType);
814     return &resReg;
815 }
816 
SelectSub(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)817 Operand *MPISel::SelectSub(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
818 {
819     PrimType primType = node.GetPrimType();
820     RegOperand &resOpnd =
821         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
822     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
823     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
824     SelectSub(resOpnd, regOpnd0, regOpnd1, primType);
825     return &resOpnd;
826 }
827 
SelectExtractbits(RegOperand &resOpnd, RegOperand &opnd0, uint8 bitOffset, uint8 bitSize, PrimType primType)828 void MPISel::SelectExtractbits(RegOperand &resOpnd, RegOperand &opnd0, uint8 bitOffset, uint8 bitSize,
829                                PrimType primType)
830 {
831     uint32 primBitSize = GetPrimTypeBitSize(primType);
832     bool isSigned = IsSignedInteger(primType);
833     if (bitOffset == 0 && !isSigned) {
834         /*
835          * resOpnd = opnd0 & ((1 << bitSize) - 1)
836          */
837         ImmOperand &imm = cgFunc->GetOpndBuilder()->CreateImm(primBitSize, (static_cast<int64>(1) << bitSize) - 1);
838         SelectBand(resOpnd, opnd0, imm, primType);
839     } else {
840         /*
841          * tmpOpnd = opnd0 << (primBitSize - bitSize - bitOffset)
842          * resOpnd = tmpOpnd >> (primBitSize - bitSize)
843          * if signed : use sar; else use shr
844          */
845         RegOperand &tmpOpnd =
846             cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
847         ImmOperand &imm1Opnd = cgFunc->GetOpndBuilder()->CreateImm(primBitSize, primBitSize - bitSize - bitOffset);
848         SelectShift(tmpOpnd, opnd0, imm1Opnd, OP_shl, primType, primType);
849         Opcode opcode = isSigned ? OP_ashr : OP_lshr;
850         ImmOperand &imm2Opnd = cgFunc->GetOpndBuilder()->CreateImm(primBitSize, primBitSize - bitSize);
851         SelectShift(resOpnd, tmpOpnd, imm2Opnd, opcode, primType, primType);
852     }
853 }
854 
SelectExtractbits(const BaseNode &parent, const ExtractbitsNode &node, Operand &opnd0)855 Operand *MPISel::SelectExtractbits(const BaseNode &parent, const ExtractbitsNode &node, Operand &opnd0)
856 {
857     PrimType fromType = node.Opnd(0)->GetPrimType();
858     PrimType toType = node.GetPrimType();
859     uint8 bitSize = node.GetBitsSize();
860     RegOperand &resOpnd =
861         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
862     if (IsPrimitiveInteger(toType)) {
863         // OP_extractbits or bitSize < 8-bit or bitSize is not pow of 2
864         if (node.GetOpCode() == OP_extractbits || bitSize < k8BitSize || (bitSize & (bitSize - 1)) != 0) {
865             SelectCopy(resOpnd, opnd0, toType, fromType);
866             SelectExtractbits(resOpnd, resOpnd, node.GetBitsOffset(), bitSize, toType);
867         } else {
868             PrimType opndType = GetIntegerPrimTypeFromSize(node.GetOpCode() == OP_sext, bitSize);
869             RegOperand &tmpRegOpnd = SelectCopy2Reg(opnd0, opndType, fromType);
870             SelectIntCvt(resOpnd, tmpRegOpnd, toType, opndType);
871         }
872     } else {
873         CHECK_FATAL(false, "NIY vector cvt");
874     }
875     return &resOpnd;
876 }
877 
SelectCvt(const BaseNode &parent, const TypeCvtNode &node, Operand &opnd0)878 Operand *MPISel::SelectCvt(const BaseNode &parent, const TypeCvtNode &node, Operand &opnd0)
879 {
880     PrimType fromType = node.Opnd(0)->GetPrimType();
881     PrimType toType = node.GetPrimType();
882     if (fromType == toType) {
883         return &opnd0;
884     }
885     RegOperand *resOpnd =
886         &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
887     if (IsPrimitiveInteger(toType) && IsPrimitiveInteger(fromType)) {
888         SelectIntCvt(*resOpnd, opnd0, toType, fromType);
889     } else if (IsPrimitiveFloat(toType) && IsPrimitiveInteger(fromType)) {
890         SelectCvtInt2Float(*resOpnd, opnd0, toType, fromType);
891     } else if (IsPrimitiveFloat(toType) && IsPrimitiveFloat(fromType)) {
892         SelectFloatCvt(*resOpnd, opnd0, toType, fromType);
893     } else if (IsPrimitiveInteger(toType) && IsPrimitiveFloat(fromType)) {
894         SelectCvtFloat2Int(*resOpnd, opnd0, toType, fromType);
895     } else {
896         CHECK_FATAL(false, "NIY cvt");
897     }
898     return resOpnd;
899 }
900 
SelectCvtFloat2Int(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)901 void MPISel::SelectCvtFloat2Int(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)
902 {
903     uint32 toSize = GetPrimTypeBitSize(toType);
904     bool isSigned = !IsPrimitiveUnsigned(toType);
905 
906     // Due to fp precision, should use one insn to perform cvt.
907     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, fromType);
908     MOperator mOp = abstract::MOP_undef;
909     switch (fromType) {
910         case PTY_f64:
911             mOp = (toSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_i32_f64 : abstract::MOP_cvt_u32_f64) :
912                                            ((isSigned) ? abstract::MOP_cvt_i64_f64 : abstract::MOP_cvt_u64_f64);
913             break;
914         case PTY_f32:
915             mOp = (toSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_i32_f32 : abstract::MOP_cvt_u32_f32) :
916                                            ((isSigned) ? abstract::MOP_cvt_i64_f32 : abstract::MOP_cvt_u64_f32);
917             break;
918         default:
919             CHECK_FATAL(false, "NYI");
920     }
921     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
922     (void)insn.AddOpndChain(resOpnd).AddOpndChain(regOpnd0);
923     cgFunc->GetCurBB()->AppendInsn(insn);
924 }
925 
SelectCvtInt2Float(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)926 void MPISel::SelectCvtInt2Float(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)
927 {
928     uint32 fromSize = GetPrimTypeBitSize(fromType);
929     bool isSigned = !IsPrimitiveUnsigned(fromType);
930     MOperator mOp = abstract::MOP_undef;
931     switch (toType) {
932         case PTY_f64:
933             mOp = (fromSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_f64_i32 : abstract::MOP_cvt_f64_u32) :
934                                              ((isSigned) ? abstract::MOP_cvt_f64_i64 : abstract::MOP_cvt_f64_u64);
935             break;
936         case PTY_f32:
937             mOp = (fromSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_f32_i32 : abstract::MOP_cvt_f32_u32) :
938                                              ((isSigned) ? abstract::MOP_cvt_f32_i64 : abstract::MOP_cvt_f32_u64);
939             break;
940         default:
941             CHECK_FATAL(false, "NYI");
942     }
943     RegOperand *regOpnd0 = nullptr;
944     if (!isSigned && fromSize <= k32BitSize && toType == PTY_f64) {
945         regOpnd0 = &cgFunc->GetOpndBuilder()->CreateVReg(k64BitSize, kRegTyInt);
946         SelectIntCvt(*regOpnd0, opnd0, maple::PTY_i64, fromType);
947     } else {
948         regOpnd0 = &SelectCopy2Reg(opnd0, fromType);
949     }
950     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
951     (void)insn.AddOpndChain(resOpnd).AddOpndChain(*regOpnd0);
952     cgFunc->GetCurBB()->AppendInsn(insn);
953 }
954 
SelectIntCvt(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)955 void MPISel::SelectIntCvt(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)
956 {
957     uint32 fromSize = GetPrimTypeBitSize(fromType);
958     uint32 toSize = GetPrimTypeBitSize(toType);
959     /*
960      * It is redundancy to insert "nop" casts (unsigned 32 -> singed 32) in abstract CG IR
961      * The signedness of operands would be shown in the expression.
962      */
963     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, fromType);
964     if (toSize <= fromSize) {
965         resOpnd = cgFunc->GetOpndBuilder()->CreateVReg(regOpnd0.GetRegisterNumber(), GetPrimTypeBitSize(toType),
966                                                        cgFunc->GetRegTyFromPrimTy(toType));
967         return;
968     }
969     bool isSigned = !IsPrimitiveUnsigned(fromType);
970     MOperator mOp = GetFastCvtMopI(fromSize, toSize, isSigned);
971     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
972     (void)insn.AddOpndChain(resOpnd).AddOpndChain(regOpnd0);
973     cgFunc->GetCurBB()->AppendInsn(insn);
974     return;
975 }
976 
SelectFloatCvt(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)977 void MPISel::SelectFloatCvt(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)
978 {
979     uint32 fromSize = GetPrimTypeBitSize(fromType);
980     uint32 toSize = GetPrimTypeBitSize(toType);
981     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, fromType);
982     if (fromSize == toSize) {
983         resOpnd = regOpnd0;
984         return;
985     }
986     MOperator mOp = abstract::MOP_undef;
987     if (fromSize == k32BitSize && toSize == k64BitSize) {
988         mOp = abstract::MOP_cvt_ff_64_32;
989     } else if (fromSize == k64BitSize && toSize == k32BitSize) {
990         mOp = abstract::MOP_cvt_ff_32_64;
991     } else {
992         CHECK_FATAL(false, "niy");
993     }
994     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
995     (void)insn.AddOpndChain(resOpnd).AddOpndChain(regOpnd0);
996     cgFunc->GetCurBB()->AppendInsn(insn);
997     return;
998 }
999 
SelectSub(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1000 void MPISel::SelectSub(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1001 {
1002     MOperator mOp = abstract::MOP_undef;
1003     if (IsPrimitiveInteger(primType)) {
1004         const static auto fastSubMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(sub);
1005         mOp = fastSubMappingFunc(GetPrimTypeBitSize(primType));
1006     } else {
1007         const static auto fastSubFloatMappingFunc = DEF_FLOAT_MOPERATOR_MAPPING_FUNC(sub);
1008         mOp = fastSubFloatMappingFunc(GetPrimTypeBitSize(primType));
1009     }
1010     SelectBasicOp(resOpnd, opnd0, opnd1, mOp, primType);
1011 }
1012 
SelectBand(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1013 void MPISel::SelectBand(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1014 {
1015     MOperator mOp = abstract::MOP_undef;
1016     if (IsPrimitiveInteger(primType)) {
1017         const static auto fastAndMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(and);
1018         mOp = fastAndMappingFunc(GetPrimTypeBitSize(primType));
1019     } else {
1020         const static auto fastAndFloatMappingFunc = DEF_FLOAT_MOPERATOR_MAPPING_FUNC(and);
1021         mOp = fastAndFloatMappingFunc(GetPrimTypeBitSize(primType));
1022     }
1023     SelectBasicOp(resOpnd, opnd0, opnd1, mOp, primType);
1024 }
1025 
SelectAdd(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1026 void MPISel::SelectAdd(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1027 {
1028     MOperator mOp = abstract::MOP_undef;
1029     if (IsPrimitiveInteger(primType)) {
1030         const static auto fastAddMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(add);
1031         mOp = fastAddMappingFunc(GetPrimTypeBitSize(primType));
1032     } else {
1033         const static auto fastAddFloatMappingFunc = DEF_FLOAT_MOPERATOR_MAPPING_FUNC(add);
1034         mOp = fastAddFloatMappingFunc(GetPrimTypeBitSize(primType));
1035     }
1036     SelectBasicOp(resOpnd, opnd0, opnd1, mOp, primType);
1037 }
1038 
SelectBior(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)1039 Operand *MPISel::SelectBior(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
1040 {
1041     PrimType primType = node.GetPrimType();
1042     RegOperand *resOpnd =
1043         &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1044     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
1045     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
1046     SelectBior(*resOpnd, regOpnd0, regOpnd1, primType);
1047     return resOpnd;
1048 }
1049 
SelectBior(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1050 void MPISel::SelectBior(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1051 {
1052     const static auto fastBiorMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(or);
1053     MOperator mOp = fastBiorMappingFunc(GetPrimTypeBitSize(primType));
1054     SelectBasicOp(resOpnd, opnd0, opnd1, mOp, primType);
1055 }
1056 
SelectBxor(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)1057 Operand *MPISel::SelectBxor(const BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
1058 {
1059     PrimType primType = node.GetPrimType();
1060     RegOperand *resOpnd =
1061         &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1062     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
1063     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
1064     SelectBxor(*resOpnd, regOpnd0, regOpnd1, primType);
1065     return resOpnd;
1066 }
1067 
SelectBxor(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1068 void MPISel::SelectBxor(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1069 {
1070     const static auto fastBxorMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(xor);
1071     MOperator mOp = fastBxorMappingFunc(GetPrimTypeBitSize(primType));
1072     SelectBasicOp(resOpnd, opnd0, opnd1, mOp, primType);
1073 }
1074 
GetOrCreateMemOpndFromIreadNode(const IreadNode &expr, PrimType primType, int offset)1075 MemOperand *MPISel::GetOrCreateMemOpndFromIreadNode(const IreadNode &expr, PrimType primType, int offset)
1076 {
1077     /* get rhs*/
1078     Operand *addrOpnd = HandleExpr(expr, *expr.Opnd(0));
1079     RegOperand &addrOnReg = SelectCopy2Reg(*addrOpnd, PTY_a64);
1080     /* Generate memOpnd */
1081     MemOperand &memOpnd = cgFunc->GetOpndBuilder()->CreateMem(addrOnReg, offset, GetPrimTypeBitSize(primType));
1082     return &memOpnd;
1083 }
1084 
SelectIread(const BaseNode &parent, const IreadNode &expr, int extraOffset)1085 Operand *MPISel::SelectIread(const BaseNode &parent, const IreadNode &expr, int extraOffset)
1086 {
1087     /* get lhs mirType info */
1088     MirTypeInfo lhsInfo = GetMirTypeInfoFromMirNode(expr);
1089     /* get memOpnd */
1090     MemOperand &memOpnd = *GetOrCreateMemOpndFromIreadNode(expr, lhsInfo.primType, lhsInfo.offset + extraOffset);
1091     /* for BasicType, load val in addr to register. */
1092     PrimType primType = expr.GetPrimType();
1093     RegOperand &result =
1094         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1095     SelectCopy(result, memOpnd, primType, lhsInfo.primType);
1096     return &result;
1097 }
1098 
SelectAbs(UnaryNode &node, Operand &opnd0)1099 Operand *MPISel::SelectAbs(UnaryNode &node, Operand &opnd0)
1100 {
1101     PrimType primType = node.GetPrimType();
1102     if (IsPrimitiveFloat(primType)) {
1103         /*
1104          * fabs(x) = x AND 0x7fffffff ffffffff [set sign bit to 0]
1105          */
1106         const static uint64 kNaN = 0x7fffffffffffffffUL;
1107         const static double kNaNDouble = *(double *)(&kNaN);
1108         const static uint64 kNaNf = 0x7fffffffUL;
1109         const static double kNaNFloat = *(double *)(&kNaNf);
1110         CHECK_FATAL(primType == PTY_f64 || primType == PTY_f32, "niy");
1111 
1112         double mask = primType == PTY_f64 ? kNaNDouble : kNaNFloat;
1113         MIRDoubleConst *c = cgFunc->GetMemoryPool()->New<MIRDoubleConst>(
1114             mask, *GlobalTables::GetTypeTable().GetTypeTable().at(PTY_f64));
1115         Operand *opnd1 = SelectFloatingConst(*c, PTY_f64);
1116 
1117         RegOperand &resOpnd =
1118             cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1119         SelectBand(resOpnd, opnd0, *opnd1, primType);
1120         return &resOpnd;
1121     } else if (IsUnsignedInteger(primType)) {
1122         return &opnd0;
1123     } else {
1124         /*
1125          * abs(x) = (x XOR y) - y
1126          * y = x >>> (bitSize - 1)
1127          */
1128         uint32 bitSize = GetPrimTypeBitSize(primType);
1129         CHECK_FATAL(bitSize == k64BitSize || bitSize == k32BitSize, "only support 32-bits or 64-bits");
1130         RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType);
1131         ImmOperand &immOpnd = cgFunc->GetOpndBuilder()->CreateImm(bitSize, bitSize - 1);
1132         RegOperand &regOpndy = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(primType));
1133         SelectShift(regOpndy, regOpnd0, immOpnd, OP_ashr, primType, primType);
1134         RegOperand &tmpOpnd = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(primType));
1135         SelectBxor(tmpOpnd, regOpnd0, regOpndy, primType);
1136         RegOperand &resOpnd = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(primType));
1137         SelectSub(resOpnd, tmpOpnd, regOpndy, primType);
1138         return &resOpnd;
1139     }
1140 }
1141 
HandleFuncEntry()1142 StmtNode *MPISel::HandleFuncEntry()
1143 {
1144     MIRFunction &mirFunc = cgFunc->GetFunction();
1145     BlockNode *block = mirFunc.GetBody();
1146 
1147     DEBUG_ASSERT(block != nullptr, "get func body block failed in CGFunc::GenerateInstruction");
1148 
1149     StmtNode *stmt = block->GetFirst();
1150     if (stmt == nullptr) {
1151         return nullptr;
1152     }
1153     DEBUG_ASSERT(stmt->GetOpCode() == OP_label, "The first statement should be a label");
1154     HandleLabel(*stmt, *this);
1155     cgFunc->SetFirstBB(*cgFunc->GetCurBB());
1156     stmt = stmt->GetNext();
1157     if (stmt == nullptr) {
1158         return nullptr;
1159     }
1160     cgFunc->SetCurBB(*cgFunc->StartNewBBImpl(false, *stmt));
1161     bool withFreqInfo = mirFunc.HasFreqMap() && !mirFunc.GetLastFreqMap().empty();
1162     if (withFreqInfo) {
1163         cgFunc->GetCurBB()->SetFrequency(kFreqBase);
1164     }
1165 
1166     return stmt;
1167 }
1168 
1169 /* This function loads src to a register, the src can be an imm, mem or a label.
1170  * Once the source and result(destination) types are different,
1171  * implicit conversion is executed here.*/
SelectCopy2Reg(Operand &src, PrimType toType, PrimType fromType)1172 RegOperand &MPISel::SelectCopy2Reg(Operand &src, PrimType toType, PrimType fromType)
1173 {
1174     uint32 fromSize = GetPrimTypeBitSize(fromType);
1175     uint32 toSize = GetPrimTypeBitSize(toType);
1176     if (src.IsRegister() && fromSize == toSize) {
1177         return static_cast<RegOperand &>(src);
1178     }
1179     RegOperand &dest =
1180         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
1181     if (fromSize != toSize) {
1182         SelectCopy(dest, src, toType, fromType);
1183     } else {
1184         SelectCopy(dest, src, toType);
1185     }
1186     return dest;
1187 }
1188 /* Pretty sure that implicit type conversions will not occur. */
SelectCopy2Reg(Operand &src, PrimType dtype)1189 RegOperand &MPISel::SelectCopy2Reg(Operand &src, PrimType dtype)
1190 {
1191     DEBUG_ASSERT(src.GetSize() == GetPrimTypeBitSize(dtype), "NIY");
1192     if (src.IsRegister()) {
1193         return static_cast<RegOperand &>(src);
1194     }
1195     RegOperand &dest =
1196         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(dtype), cgFunc->GetRegTyFromPrimTy(dtype));
1197     SelectCopy(dest, src, dtype);
1198     return dest;
1199 }
1200 /* This function copy/load/store src to a dest, Once the src and dest types
1201  * are different, implicit conversion is executed here. */
SelectCopy(Operand &dest, Operand &src, PrimType toType, PrimType fromType)1202 void MPISel::SelectCopy(Operand &dest, Operand &src, PrimType toType, PrimType fromType)
1203 {
1204     if (GetPrimTypeBitSize(fromType) != GetPrimTypeBitSize(toType)) {
1205         RegOperand &srcRegOpnd = SelectCopy2Reg(src, fromType);
1206         RegOperand &dstRegOpnd =
1207             cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
1208         SelectIntCvt(dstRegOpnd, srcRegOpnd, toType, fromType);
1209         SelectCopy(dest, dstRegOpnd, toType);
1210     } else {
1211         SelectCopy(dest, src, toType);
1212     }
1213 }
1214 
1215 /* Pretty sure that implicit type conversions will not occur. */
SelectCopy(Operand &dest, Operand &src, PrimType type)1216 void MPISel::SelectCopy(Operand &dest, Operand &src, PrimType type)
1217 {
1218     DEBUG_ASSERT(dest.GetSize() == src.GetSize(), "NIY");
1219     if (dest.GetKind() == Operand::kOpdRegister) {
1220         SelectCopyInsn(dest, src, type);
1221     } else if (dest.GetKind() == Operand::kOpdMem) {
1222         if (src.GetKind() != Operand::kOpdRegister) {
1223             RegOperand &tempReg =
1224                 cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(type), cgFunc->GetRegTyFromPrimTy(type));
1225             SelectCopyInsn(tempReg, src, type);
1226             SelectCopyInsn(dest, tempReg, type);
1227         } else {
1228             SelectCopyInsn(dest, src, type);
1229         }
1230     } else {
1231         CHECK_FATAL(false, "NIY, CPU supports more than memory and registers");
1232     }
1233     return;
1234 }
1235 
SelectCopyInsn(Operand &dest, Operand &src, PrimType type)1236 void MPISel::SelectCopyInsn(Operand &dest, Operand &src, PrimType type)
1237 {
1238     MOperator mop = GetFastIselMop(dest.GetKind(), src.GetKind(), type);
1239     CHECK_FATAL(mop != abstract::MOP_undef, "get mop failed");
1240     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mop, InsnDesc::GetAbstractId(mop));
1241     (void)insn.AddOpndChain(dest).AddOpndChain(src);
1242     cgFunc->GetCurBB()->AppendInsn(insn);
1243 }
1244 
SelectBnot(const UnaryNode &node, Operand &opnd0, const BaseNode &parent)1245 Operand *MPISel::SelectBnot(const UnaryNode &node, Operand &opnd0, const BaseNode &parent)
1246 {
1247     PrimType dtype = node.GetPrimType();
1248 
1249     RegOperand *resOpnd = nullptr;
1250     resOpnd = &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(dtype), cgFunc->GetRegTyFromPrimTy(dtype));
1251     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, dtype, node.Opnd(0)->GetPrimType());
1252     SelectBnot(*resOpnd, regOpnd0, dtype);
1253     return resOpnd;
1254 }
1255 
SelectBnot(Operand &resOpnd, Operand &opnd0, PrimType primType)1256 void MPISel::SelectBnot(Operand &resOpnd, Operand &opnd0, PrimType primType)
1257 {
1258     const static auto fastBnotMappingFunc = DEF_MOPERATOR_MAPPING_FUNC(not);
1259     MOperator mOp = fastBnotMappingFunc(GetPrimTypeBitSize(primType));
1260     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp));
1261     (void)insn.AddOpndChain(resOpnd).AddOpndChain(opnd0);
1262     cgFunc->GetCurBB()->AppendInsn(insn);
1263 }
1264 
SelectMin(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)1265 Operand *MPISel::SelectMin(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
1266 {
1267     PrimType primType = node.GetPrimType();
1268     RegOperand &resOpnd =
1269         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1270     SelectMin(resOpnd, opnd0, opnd1, primType);
1271     return &resOpnd;
1272 }
1273 
SelectMin(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1274 void MPISel::SelectMin(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1275 {
1276     SelectMinOrMax(true, resOpnd, opnd0, opnd1, primType);
1277 }
1278 
SelectMax(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)1279 Operand *MPISel::SelectMax(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
1280 {
1281     PrimType primType = node.GetPrimType();
1282     RegOperand &resOpnd =
1283         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primType), cgFunc->GetRegTyFromPrimTy(primType));
1284     SelectMax(resOpnd, opnd0, opnd1, primType);
1285     return &resOpnd;
1286 }
1287 
SelectMax(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)1288 void MPISel::SelectMax(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
1289 {
1290     SelectMinOrMax(false, resOpnd, opnd0, opnd1, primType);
1291 }
1292 
SelectRetype(TypeCvtNode &node, Operand &opnd0)1293 Operand *MPISel::SelectRetype(TypeCvtNode &node, Operand &opnd0)
1294 {
1295     PrimType fromType = node.Opnd(0)->GetPrimType();
1296     PrimType toType = node.GetPrimType();
1297     DEBUG_ASSERT(GetPrimTypeSize(fromType) == GetPrimTypeSize(toType), "retype bit widith doesn' match");
1298     if (IsPrimitivePoint(fromType) && IsPrimitivePoint(toType)) {
1299         return &SelectCopy2Reg(opnd0, toType);
1300     }
1301     if (IsPrimitiveInteger(fromType) && IsPrimitiveInteger(toType)) {
1302         return &SelectCopy2Reg(opnd0, toType, fromType);
1303     }
1304     if (IsPrimitiveInteger(fromType) && IsPrimitiveFloat(toType)) {
1305         RegOperand *resOpnd =
1306             &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
1307         SelectRetypeFloat(*resOpnd, opnd0, toType, fromType);
1308         return &(*resOpnd);
1309     }
1310     if (IsPrimitiveFloat(fromType) && IsPrimitiveInteger(toType)) {
1311         RegOperand *resOpnd =
1312             &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(toType), cgFunc->GetRegTyFromPrimTy(toType));
1313         SelectRetypeFloat(*resOpnd, opnd0, toType, fromType);
1314         return &(*resOpnd);
1315     }
1316     CHECK_FATAL(false, "NIY, retype");
1317     return nullptr;
1318 }
1319 
HandleFuncExit()1320 void MPISel::HandleFuncExit()
1321 {
1322     BlockNode *block = cgFunc->GetFunction().GetBody();
1323     DEBUG_ASSERT(block != nullptr, "get func body block failed in CGFunc::GenerateInstruction");
1324     cgFunc->GetCurBB()->SetLastStmt(*block->GetLast());
1325     /* Set lastbb's frequency */
1326     cgFunc->SetLastBB(*cgFunc->GetCurBB());
1327     /* the last BB is return BB */
1328     cgFunc->GetLastBB()->SetKind(BB::kBBReturn);
1329 }
1330 
PhaseRun(maplebe::CGFunc &f)1331 bool InstructionSelector::PhaseRun(maplebe::CGFunc &f)
1332 {
1333     MPISel *mpIS = f.GetCG()->CreateMPIsel(*GetPhaseMemPool(), *GetPhaseAllocator(), f);
1334     DEBUG_ASSERT(mpIS != nullptr, "null ptr check");
1335     mpIS->doMPIS();
1336     Standardize *stdz = f.GetCG()->CreateStandardize(*GetPhaseMemPool(), f);
1337     DEBUG_ASSERT(stdz != nullptr, "null ptr check");
1338     stdz->DoStandardize();
1339     return true;
1340 }
1341 }  // namespace maplebe
1342