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 ®AssignNode = 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 ®ReadNode = 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 ®Opnd0 = 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 ®Opnd =
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 ® = 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 ®
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 ®Opnd =
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 ®Opnd;
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 ®Opnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
801 RegOperand ®Opnd1 = 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 ®Opnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
812 RegOperand ®Opnd1 = 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 ®Opnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
823 RegOperand ®Opnd1 = 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 ®Opnd0 = 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 ®Opnd0 = 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 ®Opnd0 = 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 ®Opnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
1045 RegOperand ®Opnd1 = 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 ®Opnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
1063 RegOperand ®Opnd1 = 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 ®Opnd0 = SelectCopy2Reg(opnd0, primType);
1131 ImmOperand &immOpnd = cgFunc->GetOpndBuilder()->CreateImm(bitSize, bitSize - 1);
1132 RegOperand ®Opndy = 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 ®Opnd0 = 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