• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "x64_MPISel.h"
17 #include "x64_isa_tbl.h"
18 #include "x64_cg.h"
19 
20 namespace maplebe {
21 /* Field-ID 0 is assigned to the top level structure. (Field-ID also defaults to 0 if it is not a structure.) */
GetOrCreateMemOpndFromSymbol(const MIRSymbol & symbol,FieldID fieldId) const22 MemOperand &X64MPIsel::GetOrCreateMemOpndFromSymbol(const MIRSymbol &symbol, FieldID fieldId) const
23 {
24     PrimType symType;
25     int32 fieldOffset = 0;
26     CHECK_FATAL(fieldId == 0, "fieldId must be 0");
27     symType = symbol.GetType()->GetPrimType();
28     uint32 opndSz = GetPrimTypeBitSize(symType);
29     return GetOrCreateMemOpndFromSymbol(symbol, opndSz, fieldOffset);
30 }
GetOrCreateMemOpndFromSymbol(const MIRSymbol & symbol,uint32 opndSize,int64 offset) const31 MemOperand &X64MPIsel::GetOrCreateMemOpndFromSymbol(const MIRSymbol &symbol, uint32 opndSize, int64 offset) const
32 {
33     MIRStorageClass storageClass = symbol.GetStorageClass();
34     MemOperand *result = nullptr;
35     RegOperand *stackBaseReg = nullptr;
36     if ((storageClass == kScAuto) || (storageClass == kScFormal)) {
37         auto *symloc = static_cast<X64SymbolAlloc *>(cgFunc->GetMemlayout()->GetSymAllocInfo(symbol.GetStIndex()));
38         DEBUG_ASSERT(symloc != nullptr, "sym loc should have been defined");
39         stackBaseReg = static_cast<X64CGFunc *>(cgFunc)->GetBaseReg(*symloc);
40         int stOfst = cgFunc->GetBaseOffset(*symloc);
41         /* Create field symbols in aggregate structure */
42         result = &GetCurFunc()->GetOpndBuilder()->CreateMem(opndSize);
43         result->SetBaseRegister(*stackBaseReg);
44         result->SetOffsetOperand(GetCurFunc()->GetOpndBuilder()->CreateImm(k64BitSize, stOfst + offset));
45         CHECK_FATAL(result != nullptr, "NIY");
46         return *result;
47     }
48     if ((storageClass == kScGlobal) || (storageClass == kScExtern) || (storageClass == kScPstatic) ||
49         (storageClass == kScFstatic)) {
50         stackBaseReg = &GetCurFunc()->GetOpndBuilder()->CreatePReg(x64::RIP, k64BitSize, kRegTyInt);
51         result = &GetCurFunc()->GetOpndBuilder()->CreateMem(opndSize);
52         ImmOperand &stOfstOpnd = GetCurFunc()->GetOpndBuilder()->CreateImm(symbol, offset, 0);
53         result->SetBaseRegister(*stackBaseReg);
54         result->SetOffsetOperand(stOfstOpnd);
55         CHECK_FATAL(result != nullptr, "NIY");
56         return *result;
57     }
58     CHECK_FATAL(false, "NIY");
59     return *result;
60 }
61 
SelectReturn(NaryStmtNode & retNode,Operand & opnd)62 void X64MPIsel::SelectReturn(NaryStmtNode &retNode, Operand &opnd)
63 {
64     MIRType *retType = cgFunc->GetFunction().GetReturnType();
65     X64CallConvImpl retLocator(cgFunc->GetBecommon());
66     CCLocInfo retMech;
67     retLocator.LocateRetVal(*retType, retMech);
68     if (retMech.GetRegCount() == 0) {
69         return;
70     }
71     std::vector<RegOperand *> retRegs;
72     PrimType oriPrimType = retMech.GetPrimTypeOfReg0();
73     regno_t retReg = retMech.GetReg0();
74     DEBUG_ASSERT(retReg != kRinvalid, "NIY");
75     RegOperand &retOpnd = cgFunc->GetOpndBuilder()->CreatePReg(retReg, GetPrimTypeBitSize(oriPrimType),
76                                                                cgFunc->GetRegTyFromPrimTy(oriPrimType));
77     retRegs.push_back(&retOpnd);
78     SelectCopy(retOpnd, opnd, oriPrimType, retNode.Opnd(0)->GetPrimType());
79     /* for optimization ,insert pseudo ret ,in case rax,rdx is removed*/
80     SelectPseduoForReturn(retRegs);
81 }
82 
SelectPseduoForReturn(std::vector<RegOperand * > & retRegs)83 void X64MPIsel::SelectPseduoForReturn(std::vector<RegOperand *> &retRegs)
84 {
85     for (auto retReg : retRegs) {
86         MOperator mop = x64::MOP_pseudo_ret_int;
87         Insn &pInsn = cgFunc->GetInsnBuilder()->BuildInsn(mop, X64CG::kMd[mop]);
88         cgFunc->GetCurBB()->AppendInsn(pInsn);
89         pInsn.AddOpndChain(*retReg);
90     }
91 }
92 
SelectReturn()93 void X64MPIsel::SelectReturn()
94 {
95     /* jump to epilogue */
96     MOperator mOp = x64::MOP_jmpq_l;
97     LabelNode *endLabel = cgFunc->GetEndLabel();
98     auto endLabelName = ".L." + std::to_string(cgFunc->GetUniqueID()) + "__" + std::to_string(endLabel->GetLabelIdx());
99     LabelOperand &targetOpnd = cgFunc->GetOpndBuilder()->CreateLabel(endLabelName.c_str(), endLabel->GetLabelIdx());
100     Insn &jmpInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
101     jmpInsn.AddOpndChain(targetOpnd);
102     cgFunc->GetCurBB()->AppendInsn(jmpInsn);
103     cgFunc->GetExitBBsVec().emplace_back(cgFunc->GetCurBB());
104 }
105 
106 /*
107  * SelectParmList generates an instrunction for each of the parameters
108  * to load the parameter value into the corresponding register.
109  * We return a list of registers to the call instruction because
110  * they may be needed in the register allocation phase.
111  * fp Num is a return value which is the number of vector
112  * registers used;
113  */
SelectParmList(StmtNode & naryNode,ListOperand & srcOpnds,uint32 & fpNum)114 void X64MPIsel::SelectParmList(StmtNode &naryNode, ListOperand &srcOpnds, uint32 &fpNum)
115 {
116     paramPassByReg.clear();
117     fpNum = 0;
118     /* for IcallNode, the 0th operand is the function pointer */
119     size_t argBegin = 0;
120     if (naryNode.GetOpCode() == OP_icall || naryNode.GetOpCode() == OP_icallproto ||
121         naryNode.GetOpCode() == OP_tailicall) {
122         ++argBegin;
123     }
124 
125     MIRFunction *callee = nullptr;
126     if (naryNode.GetOpCode() == OP_call) {
127         PUIdx calleePuIdx = static_cast<CallNode &>(naryNode).GetPUIdx();
128         callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(calleePuIdx);
129     }
130     X64CallConvImpl parmLocator(cgFunc->GetBecommon(), X64CallConvImpl::GetCallConvKind(naryNode));
131     CCLocInfo ploc;
132     for (size_t i = argBegin; i < naryNode.NumOpnds(); ++i) {
133         BaseNode *argExpr = naryNode.Opnd(i);
134         DEBUG_ASSERT(argExpr != nullptr, "not null check");
135         PrimType primType = argExpr->GetPrimType();
136         DEBUG_ASSERT(primType != PTY_void, "primType should not be void");
137         bool isArgUnused = (callee != nullptr && callee->GetFuncDesc().IsArgUnused(i));
138 
139         Operand *argOpnd = HandleExpr(naryNode, *argExpr);
140         DEBUG_ASSERT(argOpnd != nullptr, "not null check");
141         MIRType *mirType = GlobalTables::GetTypeTable().GetTypeTable()[static_cast<uint32>(primType)];
142         parmLocator.LocateNextParm(*mirType, ploc);
143 
144         /* skip unused args */
145         if (isArgUnused) {
146             continue;
147         }
148 
149         if (ploc.reg0 != x64::kRinvalid) {
150             /* load to the register. */
151             RegOperand &parmRegOpnd = cgFunc->GetOpndBuilder()->CreatePReg(ploc.reg0, GetPrimTypeBitSize(primType),
152                                                                            cgFunc->GetRegTyFromPrimTy(primType));
153             paramPassByReg.push_back({&parmRegOpnd, argOpnd, primType});
154             if (x64::IsFPSIMDRegister(static_cast<X64reg>(ploc.reg0))) {
155                 fpNum++;
156             }
157         } else {
158             /* load to stack memory */
159             RegOperand &baseOpnd =
160                 cgFunc->GetOpndBuilder()->CreatePReg(x64::RSP, k64BitSize, cgFunc->GetRegTyFromPrimTy(primType));
161             MemOperand &actMemOpnd =
162                 cgFunc->GetOpndBuilder()->CreateMem(baseOpnd, ploc.memOffset, GetPrimTypeBitSize(primType));
163             SelectCopy(actMemOpnd, *argOpnd, primType);
164         }
165         DEBUG_ASSERT(ploc.reg1 == 0, "SelectCall NIY");
166     }
167 
168     /* param pass by reg */
169     for (auto [regOpnd, argOpnd, primType] : paramPassByReg) {
170         DEBUG_ASSERT(regOpnd != nullptr, "not null check");
171         DEBUG_ASSERT(argOpnd != nullptr, "not null check");
172         SelectCopy(*regOpnd, *argOpnd, primType);
173         srcOpnds.PushOpnd(*regOpnd);
174     }
175 }
176 
SelectSpecialRegread(PregIdx pregIdx,PrimType primType)177 RegOperand &X64MPIsel::SelectSpecialRegread(PregIdx pregIdx, PrimType primType)
178 {
179     switch (-pregIdx) {
180         case kSregFp: {
181             return cgFunc->GetOpndBuilder()->CreatePReg(x64::RFP, k64BitSize, cgFunc->GetRegTyFromPrimTy(primType));
182         }
183         case kSregSp: {
184             return cgFunc->GetOpndBuilder()->CreatePReg(x64::RSP, k64BitSize, cgFunc->GetRegTyFromPrimTy(primType));
185         }
186         default: {
187             CHECK_FATAL(false, "ERROR: Not supported special register!");
188         }
189     }
190 }
191 
SelectFloatingConst(MIRConst & floatingConst,PrimType primType) const192 Operand *X64MPIsel::SelectFloatingConst(MIRConst &floatingConst, PrimType primType) const
193 {
194     CHECK_FATAL(primType == PTY_f64 || primType == PTY_f32, "wrong const");
195     uint32 labelIdxTmp = cgFunc->GetLabelIdx();
196     Operand *result = nullptr;
197     if (primType == PTY_f64) {
198         result = SelectLiteral(static_cast<MIRDoubleConst &>(floatingConst), cgFunc->GetFunction(), labelIdxTmp++);
199     } else {
200         result = SelectLiteral(static_cast<MIRFloatConst &>(floatingConst), cgFunc->GetFunction(), labelIdxTmp++);
201     }
202     cgFunc->SetLabelIdx(labelIdxTmp);
203     return result;
204 }
205 
AppendCall(x64::X64MOP_t mOp,Operand & targetOpnd,ListOperand & paramOpnds,ListOperand & retOpnds)206 Insn &X64MPIsel::AppendCall(x64::X64MOP_t mOp, Operand &targetOpnd, ListOperand &paramOpnds, ListOperand &retOpnds)
207 {
208     Insn &callInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
209     callInsn.AddOpndChain(targetOpnd).AddOpndChain(paramOpnds).AddOpndChain(retOpnds);
210     cgFunc->GetCurBB()->AppendInsn(callInsn);
211     cgFunc->GetCurBB()->SetHasCall();
212     cgFunc->GetFunction().SetHasCall();
213     return callInsn;
214 }
215 
SelectCalleeReturn(MIRType * retType,ListOperand & retOpnds)216 void X64MPIsel::SelectCalleeReturn(MIRType *retType, ListOperand &retOpnds)
217 {
218     if (retType == nullptr) {
219         return;
220     }
221     auto retSize = retType->GetSize() * kBitsPerByte;
222     if (retSize <= k128BitSize) {
223         if (retSize > k0BitSize) {
224             retOpnds.PushOpnd(cgFunc->GetOpndBuilder()->CreatePReg(x64::RAX, k64BitSize, kRegTyInt));
225         }
226         if (retSize > k64BitSize) {
227             retOpnds.PushOpnd(cgFunc->GetOpndBuilder()->CreatePReg(x64::RDX, k64BitSize, kRegTyInt));
228         }
229     }
230 }
231 
SelectCall(CallNode & callNode)232 void X64MPIsel::SelectCall(CallNode &callNode)
233 {
234     MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx());
235     MIRSymbol *fsym = GlobalTables::GetGsymTable().GetSymbolFromStidx(fn->GetStIdx().Idx(), false);
236     Operand &targetOpnd = cgFunc->GetOpndBuilder()->CreateFuncNameOpnd(*fsym);
237 
238     ListOperand &paramOpnds = cgFunc->GetOpndBuilder()->CreateList();
239     uint32 fpNum = 0;
240     SelectParmList(callNode, paramOpnds, fpNum);
241     /* x64abi: rax = with variable arguments passes information about the number of vector registers used */
242     if (fn->IsVarargs()) {
243         ImmOperand &fpNumImm = cgFunc->GetOpndBuilder()->CreateImm(k64BitSize, fpNum);
244         RegOperand &raxOpnd = cgFunc->GetOpndBuilder()->CreatePReg(x64::RAX, k64BitSize, kRegTyInt);
245         SelectCopy(raxOpnd, fpNumImm, PTY_i64);
246     }
247 
248     MIRType *retType = fn->GetReturnType();
249     ListOperand &retOpnds = cgFunc->GetOpndBuilder()->CreateList();
250     SelectCalleeReturn(retType, retOpnds);
251 
252     Insn &callInsn = AppendCall(x64::MOP_callq_l, targetOpnd, paramOpnds, retOpnds);
253     if (retType != nullptr) {
254         callInsn.SetRetSize(static_cast<uint32>(retType->GetSize()));
255         callInsn.SetIsCallReturnUnsigned(IsUnsignedInteger(retType->GetPrimType()));
256     }
257     const auto &deoptBundleInfo = callNode.GetDeoptBundleInfo();
258     for (const auto &elem : deoptBundleInfo) {
259         auto valueKind = elem.second.GetMapleValueKind();
260         if (valueKind == MapleValue::kPregKind) {
261             auto *opnd = cgFunc->GetOrCreateRegOpndFromPregIdx(elem.second.GetPregIdx(), PTY_ref);
262             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
263         } else if (valueKind == MapleValue::kConstKind) {
264             auto *opnd = SelectIntConst(static_cast<const MIRIntConst &>(elem.second.GetConstValue()), PTY_i32);
265             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
266         } else {
267             CHECK_FATAL(false, "not supported currently");
268         }
269     }
270     cgFunc->AppendStackMapInsn(callInsn);
271 }
272 
SelectIcall(IcallNode & iCallNode)273 void X64MPIsel::SelectIcall(IcallNode &iCallNode)
274 {
275     Operand *opnd0 = HandleExpr(iCallNode, *iCallNode.GetNopndAt(0));
276     RegOperand &targetOpnd = SelectCopy2Reg(*opnd0, iCallNode.Opnd(0)->GetPrimType());
277     ListOperand &paramOpnds = cgFunc->GetOpndBuilder()->CreateList();
278     uint32 fpNum = 0;
279     SelectParmList(iCallNode, paramOpnds, fpNum);
280 
281     MIRType *retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iCallNode.GetRetTyIdx());
282     if (iCallNode.GetOpCode() == OP_icallproto) {
283         CHECK_FATAL((retType->GetKind() == kTypeFunction), "NIY, must be func");
284         auto calleeType = static_cast<MIRFuncType *>(retType);
285         retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(calleeType->GetRetTyIdx());
286     }
287     ListOperand &retOpnds = cgFunc->GetOpndBuilder()->CreateList();
288     SelectCalleeReturn(retType, retOpnds);
289 
290     Insn &callInsn = AppendCall(x64::MOP_callq_r, targetOpnd, paramOpnds, retOpnds);
291     if (retType != nullptr) {
292         callInsn.SetRetSize(static_cast<uint32>(retType->GetSize()));
293         callInsn.SetIsCallReturnUnsigned(IsUnsignedInteger(retType->GetPrimType()));
294     }
295     const auto &deoptBundleInfo = iCallNode.GetDeoptBundleInfo();
296     for (const auto &elem : deoptBundleInfo) {
297         auto valueKind = elem.second.GetMapleValueKind();
298         if (valueKind == MapleValue::kPregKind) {
299             auto *opnd = cgFunc->GetOrCreateRegOpndFromPregIdx(elem.second.GetPregIdx(), PTY_ref);
300             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
301         } else if (valueKind == MapleValue::kConstKind) {
302             auto *opnd = SelectIntConst(static_cast<const MIRIntConst &>(elem.second.GetConstValue()), PTY_i32);
303             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
304         } else {
305             CHECK_FATAL(false, "not supported currently");
306         }
307     }
308     cgFunc->AppendStackMapInsn(callInsn);
309 }
310 
ProcessReturnReg(PrimType primType,int32 sReg)311 Operand &X64MPIsel::ProcessReturnReg(PrimType primType, int32 sReg)
312 {
313     return GetTargetRetOperand(primType, sReg);
314 }
315 
SelectGoto(GotoNode & stmt)316 void X64MPIsel::SelectGoto(GotoNode &stmt)
317 {
318     MOperator mOp = x64::MOP_jmpq_l;
319     auto funcName = ".L." + std::to_string(cgFunc->GetUniqueID()) + "__" + std::to_string(stmt.GetOffset());
320     LabelOperand &targetOpnd = cgFunc->GetOpndBuilder()->CreateLabel(funcName.c_str(), stmt.GetOffset());
321     Insn &jmpInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
322     cgFunc->GetCurBB()->AppendInsn(jmpInsn);
323     jmpInsn.AddOpndChain(targetOpnd);
324     cgFunc->GetCurBB()->SetKind(BB::kBBGoto);
325     return;
326 }
327 
SelectOverFlowCall(const IntrinsiccallNode & intrnNode)328 void X64MPIsel::SelectOverFlowCall(const IntrinsiccallNode &intrnNode)
329 {
330     DEBUG_ASSERT(intrnNode.NumOpnds() == kOpndNum2, "must be 2 operands");
331     MIRIntrinsicID intrinsic = intrnNode.GetIntrinsic();
332     // add
333     PrimType type = intrnNode.Opnd(0)->GetPrimType();
334     PrimType type2 = intrnNode.Opnd(1)->GetPrimType();
335     CHECK_FATAL(type == PTY_i32 || type == PTY_u32, "only support i32 or u32 here");
336     CHECK_FATAL(type2 == PTY_i32 || type2 == PTY_u32, "only support i32 or u32 here");
337     RegOperand &opnd0 = SelectCopy2Reg(*HandleExpr(intrnNode, *intrnNode.Opnd(0)),
338                                        intrnNode.Opnd(0)->GetPrimType()); /* first argument of intrinsic */
339     RegOperand &opnd1 = SelectCopy2Reg(*HandleExpr(intrnNode, *intrnNode.Opnd(1)),
340                                        intrnNode.Opnd(1)->GetPrimType()); /* first argument of intrinsic */
341     RegOperand &resReg =
342         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(type), cgFunc->GetRegTyFromPrimTy(type));
343     if (intrinsic == INTRN_ADD_WITH_OVERFLOW) {
344         SelectAdd(resReg, opnd0, opnd1, type);
345     } else if (intrinsic == INTRN_SUB_WITH_OVERFLOW) {
346         SelectSub(resReg, opnd0, opnd1, type);
347     } else if (intrinsic == INTRN_MUL_WITH_OVERFLOW) {
348         SelectMpy(resReg, opnd0, opnd1, type);
349     } else {
350         CHECK_FATAL(false, "niy");
351     }
352 
353     // store
354     auto *p2nrets = &intrnNode.GetReturnVec();
355     if (p2nrets->size() == k2ByteSize) {
356         CHECK_NULL_FATAL(cgFunc->GetBecommon().GetMIRModule().CurFunction());
357         PregIdx pregIdx = (*p2nrets)[0].second.GetPregIdx();
358         MIRPreg *mirPreg = cgFunc->GetFunction().GetPregTab()->PregFromPregIdx(pregIdx);
359         PrimType regType = mirPreg->GetPrimType();
360         RegOperand &retReg = cgFunc->GetOpndBuilder()->CreateVReg(cgFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx),
361             GetPrimTypeBitSize(regType), cgFunc->GetRegTyFromPrimTy(regType));
362         SelectCopy(retReg, resReg, type);
363         PregIdx pregIdx2 = (*p2nrets)[1].second.GetPregIdx();
364         MIRPreg *mirPreg2 = cgFunc->GetFunction().GetPregTab()->PregFromPregIdx(pregIdx2);
365         PrimType regType2 = mirPreg2->GetPrimType();
366         RegOperand &retReg2 = cgFunc->GetOpndBuilder()->CreateVReg(cgFunc->GetVirtualRegNOFromPseudoRegIdx(pregIdx2),
367             GetPrimTypeBitSize(regType2), cgFunc->GetRegTyFromPrimTy(regType2));
368         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(MOP_seto_r, X64CG::kMd[MOP_seto_r]);
369         insn.AddOpndChain(retReg2);
370         cgFunc->GetCurBB()->AppendInsn(insn);
371     } else {
372         CHECK_FATAL(false, "should not happen");
373     }
374     return;
375 }
376 
SelectPureCall(const IntrinsiccallNode & intrnNode)377 void X64MPIsel::SelectPureCall(const IntrinsiccallNode &intrnNode)
378 {
379     DEBUG_ASSERT(intrnNode.NumOpnds() == 6, "must be 6 operands");  // must be 6 operands
380     ListOperand &srcOpnds = cgFunc->GetOpndBuilder()->CreateList();
381     auto &callee = *intrnNode.Opnd(0);
382     auto ptyp = callee.GetPrimType();
383     RegOperand &calleeReg = SelectCopy2Reg(*HandleExpr(intrnNode, callee), ptyp);
384     uint32 i = 1;
385     for (; i < kSeventhReg; i++) {
386         srcOpnds.PushOpnd(LoadOpndIntoPhysicalRegister(intrnNode, i));
387     }
388     // R11 is used in asm call
389     srcOpnds.PushOpnd(cgFunc->GetOpndBuilder()->CreatePReg(x64::R11, GetPrimTypeBitSize(PTY_i64), kRegTyInt));
390     MOperator mOp = x64::MOP_pure_call;
391     Insn &callInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
392     callInsn.AddOpndChain(calleeReg);
393     callInsn.AddOpndChain(srcOpnds);
394     cgFunc->GetCurBB()->AppendInsn(callInsn);
395     return;
396 }
397 
LoadOpndIntoPhysicalRegister(const IntrinsiccallNode & intrnNode,uint32 index)398 RegOperand &X64MPIsel::LoadOpndIntoPhysicalRegister(const IntrinsiccallNode &intrnNode, uint32 index)
399 {
400     auto &opnd = *intrnNode.Opnd(index);
401     auto ptyp = opnd.GetPrimType();
402     RegOperand &opndReg = SelectCopy2Reg(*HandleExpr(intrnNode, opnd), ptyp);
403     PRegNo regId;
404     switch (index - 1) {
405         case kFirstReg:
406             regId = x64::RDI;
407             break;
408         case kSecondReg:
409             regId = x64::RSI;
410             break;
411         case kThirdReg:
412             regId = x64::RDX;
413             break;
414         case kFourthReg:
415             regId = x64::RCX;
416             break;
417         case kFifthReg:
418             regId = x64::R8;
419             break;
420         case kSixthReg:
421             regId = x64::R9;
422             break;
423         default:
424             CHECK_FATAL_FALSE("Unreachable!");
425     }
426     RegOperand &realReg = cgFunc->GetOpndBuilder()->CreatePReg(regId, GetPrimTypeBitSize(PTY_i64), kRegTyInt);
427     SelectCopy(realReg, opndReg, ptyp, ptyp);
428     return realReg;
429 }
430 
SelectIntrinsicCall(IntrinsiccallNode & intrinsiccallNode)431 void X64MPIsel::SelectIntrinsicCall(IntrinsiccallNode &intrinsiccallNode)
432 {
433     MIRIntrinsicID intrinsic = intrinsiccallNode.GetIntrinsic();
434     if (intrinsic == INTRN_ADD_WITH_OVERFLOW || intrinsic == INTRN_SUB_WITH_OVERFLOW ||
435         intrinsic == INTRN_MUL_WITH_OVERFLOW) {
436         SelectOverFlowCall(intrinsiccallNode);
437         return;
438     }
439     if (intrinsic == maple::INTRN_JS_PURE_CALL) {
440         SelectPureCall(intrinsiccallNode);
441         return;
442     }
443 
444     CHECK_FATAL(false, "Intrinsic %d: %s not implemented by the X64 CG.", intrinsic, GetIntrinsicName(intrinsic));
445 }
446 
SelectDeoptCall(CallNode & callNode)447 void X64MPIsel::SelectDeoptCall(CallNode &callNode)
448 {
449     MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx());
450     MIRSymbol *fsym = GlobalTables::GetGsymTable().GetSymbolFromStidx(fn->GetStIdx().Idx(), false);
451     Operand &targetOpnd = cgFunc->GetOpndBuilder()->CreateFuncNameOpnd(*fsym);
452 
453     ListOperand &paramOpnds = cgFunc->GetOpndBuilder()->CreateList();
454     uint32 fpNum = 0;
455     SelectParmList(callNode, paramOpnds, fpNum);
456     /* x64abi: rax = with variable arguments passes information about the number of vector registers used */
457     if (fn->IsVarargs()) {
458         ImmOperand &fpNumImm = cgFunc->GetOpndBuilder()->CreateImm(k64BitSize, fpNum);
459         RegOperand &raxOpnd = cgFunc->GetOpndBuilder()->CreatePReg(x64::RAX, k64BitSize, kRegTyInt);
460         SelectCopy(raxOpnd, fpNumImm, PTY_i64);
461     }
462     ListOperand &retOpnds = cgFunc->GetOpndBuilder()->CreateList();
463     Insn &callInsn = AppendCall(x64::MOP_callq_l, targetOpnd, paramOpnds, retOpnds);
464     const auto &deoptBundleInfo = callNode.GetDeoptBundleInfo();
465     for (const auto &elem : deoptBundleInfo) {
466         auto valueKind = elem.second.GetMapleValueKind();
467         if (valueKind == MapleValue::kPregKind) {
468             auto *opnd = cgFunc->GetOrCreateRegOpndFromPregIdx(elem.second.GetPregIdx(), PTY_ref);
469             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
470         } else if (valueKind == MapleValue::kConstKind) {
471             auto *opnd = SelectIntConst(static_cast<const MIRIntConst &>(elem.second.GetConstValue()), PTY_i32);
472             callInsn.AddDeoptBundleInfo(elem.first, *opnd);
473         } else {
474             CHECK_FATAL(false, "not supported currently");
475         }
476     }
477     cgFunc->AppendStackMapInsn(callInsn);
478 }
479 
SelectTailICall(IcallNode & icallNode)480 void X64MPIsel::SelectTailICall(IcallNode &icallNode)
481 {
482     Operand *opnd0 = HandleExpr(icallNode, *icallNode.GetNopndAt(0));
483     RegOperand &targetOpnd = SelectCopy2Reg(*opnd0, icallNode.Opnd(0)->GetPrimType());
484     ListOperand &paramOpnds = cgFunc->GetOpndBuilder()->CreateList();
485     uint32 fpNum = 0;
486     SelectParmList(icallNode, paramOpnds, fpNum);
487     Insn &callInsn = cgFunc->GetInsnBuilder()->BuildInsn(x64::MOP_tail_callq_r, targetOpnd, paramOpnds);
488     cgFunc->GetCurBB()->AppendInsn(callInsn);
489 }
490 
SelectRangeGoto(RangeGotoNode & rangeGotoNode,Operand & srcOpnd)491 void X64MPIsel::SelectRangeGoto(RangeGotoNode &rangeGotoNode, Operand &srcOpnd)
492 {
493     MIRType *etype = GlobalTables::GetTypeTable().GetTypeFromTyIdx((TyIdx)PTY_a64);
494     std::vector<uint64> sizeArray;
495     const SmallCaseVector &switchTable = rangeGotoNode.GetRangeGotoTable();
496     sizeArray.emplace_back(switchTable.size());
497     MemPool *memPool = cgFunc->GetMemoryPool();
498     MIRArrayType *arrayType = memPool->New<MIRArrayType>(etype->GetTypeIndex(), sizeArray);
499     MIRAggConst *arrayConst = memPool->New<MIRAggConst>(cgFunc->GetMirModule(), *arrayType);
500     for (const auto &itPair : switchTable) {
501         LabelIdx labelIdx = itPair.second;
502         cgFunc->GetCurBB()->PushBackRangeGotoLabel(labelIdx);
503         MIRConst *mirConst = memPool->New<MIRLblConst>(labelIdx, cgFunc->GetFunction().GetPuidx(), *etype);
504         arrayConst->AddItem(mirConst, 0);
505     }
506     MIRSymbol *lblSt = cgFunc->GetFunction().GetSymTab()->CreateSymbol(kScopeLocal);
507     lblSt->SetStorageClass(kScFstatic);
508     lblSt->SetSKind(kStConst);
509     lblSt->SetTyIdx(arrayType->GetTypeIndex());
510     lblSt->SetKonst(arrayConst);
511     std::string lblStr(".L_");
512     uint32 labelIdxTmp = cgFunc->GetLabelIdx();
513     lblStr.append(std::to_string(cgFunc->GetUniqueID())).append("_LOCAL_CONST.").append(std::to_string(labelIdxTmp++));
514     cgFunc->SetLabelIdx(labelIdxTmp);
515     lblSt->SetNameStrIdx(lblStr);
516     cgFunc->AddEmitSt(cgFunc->GetCurBB()->GetId(), *lblSt);
517     ImmOperand &stOpnd = cgFunc->GetOpndBuilder()->CreateImm(*lblSt, 0, 0);
518     /* get index */
519     PrimType srcType = rangeGotoNode.Opnd(0)->GetPrimType();
520     RegOperand &opnd0 = SelectCopy2Reg(srcOpnd, srcType);
521     int32 minIdx = switchTable[0].first;
522     ImmOperand &opnd1 =
523         cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(srcType), -minIdx - rangeGotoNode.GetTagOffset());
524     RegOperand &indexOpnd = cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(srcType), kRegTyInt);
525     SelectAdd(indexOpnd, opnd0, opnd1, srcType);
526 
527     /* load the displacement into a register by accessing memory at base + index * 8 */
528     /* mov .L_xxx_LOCAL_CONST.x(%baseReg, %indexOpnd, 8), %dstRegOpnd */
529     MemOperand &dstMemOpnd = cgFunc->GetOpndBuilder()->CreateMem(GetPrimTypeBitSize(PTY_a64));
530     RegOperand &baseReg = cgFunc->GetOpndBuilder()->CreatePReg(x64::RBP, GetPrimTypeBitSize(PTY_i64), kRegTyInt);
531     dstMemOpnd.SetBaseRegister(baseReg);
532     dstMemOpnd.SetIndexRegister(indexOpnd);
533     dstMemOpnd.SetOffsetOperand(stOpnd);
534     dstMemOpnd.SetScaleOperand(cgFunc->GetOpndBuilder()->CreateImm(baseReg.GetSize(), k8ByteSize));
535 
536     /* jumping to the absolute address which is stored in dstRegOpnd */
537     MOperator mOp = x64::MOP_jmpq_m;
538     Insn &jmpInsn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
539     jmpInsn.AddOpndChain(dstMemOpnd);
540     cgFunc->GetCurBB()->AppendInsn(jmpInsn);
541 }
542 
543 /*
544  * unorded   ZF, PF, CF  ==> 1,1,1
545  * above     ZF, PF, CF  ==> 0,0,0
546  * below     ZF, PF, CF  ==> 0,0,1
547  * equal     ZF, PF, CF  ==> 1,0,0
548  *
549  * To distinguish between less than(only check whether CF = 1 or not) and unorderd(CF=1),
550  * So ** judging gt/ge by swaping operands is used to represent lt/le in float**
551  */
PickJmpInsn(Opcode brOp,Opcode cmpOp,bool isFloat,bool isSigned)552 static X64MOP_t PickJmpInsn(Opcode brOp, Opcode cmpOp, bool isFloat, bool isSigned)
553 {
554     switch (cmpOp) {
555         case OP_ne:
556             return (brOp == OP_brtrue) ? MOP_jne_l : MOP_je_l;
557         case OP_eq:
558             return (brOp == OP_brtrue) ? MOP_je_l : MOP_jne_l;
559         case OP_lt:
560             return (brOp == OP_brtrue) ? (isFloat ? MOP_ja_l : (isSigned ? MOP_jl_l : MOP_jb_l))
561                                        : (isSigned ? MOP_jge_l : MOP_jae_l);
562         case OP_le:
563             return (brOp == OP_brtrue) ? (isFloat ? MOP_jae_l : (isSigned ? MOP_jle_l : MOP_jbe_l))
564                                        : (isSigned ? MOP_jg_l : MOP_ja_l);
565         case OP_gt:
566             return (brOp == OP_brtrue) ? (isFloat ? MOP_ja_l : (isSigned ? MOP_jg_l : MOP_ja_l))
567                                        : (isSigned ? MOP_jle_l : MOP_jbe_l);
568         case OP_ge:
569             return (brOp == OP_brtrue) ? (isSigned ? MOP_jge_l : MOP_jae_l) : (isSigned ? MOP_jl_l : MOP_jb_l);
570         default:
571             CHECK_FATAL(false, "PickJmpInsn error");
572     }
573 }
574 
575 /*
576  * handle brfalse/brtrue op, opnd0 can be a compare node or non-compare node
577  * such as a dread for example
578  */
SelectCondGoto(CondGotoNode & stmt,BaseNode & condNode,Operand & opnd0)579 void X64MPIsel::SelectCondGoto(CondGotoNode &stmt, BaseNode &condNode, Operand &opnd0)
580 {
581     Opcode opcode = stmt.GetOpCode();
582     X64MOP_t jmpOperator = x64::MOP_begin;
583     if (opnd0.IsImmediate()) {
584         DEBUG_ASSERT(opnd0.IsIntImmediate(), "only support int immediate");
585         DEBUG_ASSERT(opcode == OP_brtrue || opcode == OP_brfalse, "unsupported opcode");
586         ImmOperand &immOpnd0 = static_cast<ImmOperand &>(opnd0);
587         if ((opcode == OP_brtrue && !(immOpnd0.GetValue() != 0)) ||
588             (opcode == OP_brfalse && !(immOpnd0.GetValue() == 0))) {
589             return;
590         }
591         jmpOperator = x64::MOP_jmpq_l;
592         cgFunc->SetCurBBKind(BB::kBBGoto);
593     } else {
594         PrimType primType;
595         Opcode condOpcode = condNode.GetOpCode();
596         // op_ne
597         if (!kOpcodeInfo.IsCompare(condOpcode)) {
598             primType = condNode.GetPrimType();
599             ImmOperand &imm0 = cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(primType), 0);
600             SelectCmp(opnd0, imm0, primType);
601             condOpcode = OP_ne;
602         } else {
603             primType = static_cast<CompareNode &>(condNode).GetOpndType();
604         }
605         bool isFloat = IsPrimitiveFloat(primType);
606         jmpOperator = PickJmpInsn(opcode, condOpcode, isFloat, IsSignedInteger(primType));
607         cgFunc->SetCurBBKind(BB::kBBIf);
608     }
609     /* gen targetOpnd, .L.xxx__xx */
610     auto funcName = ".L." + std::to_string(cgFunc->GetUniqueID()) + "__" + std::to_string(stmt.GetOffset());
611     LabelOperand &targetOpnd = cgFunc->GetOpndBuilder()->CreateLabel(funcName.c_str(), stmt.GetOffset());
612     /* select jump Insn */
613     Insn &jmpInsn = (cgFunc->GetInsnBuilder()->BuildInsn(jmpOperator, X64CG::kMd[jmpOperator]));
614     jmpInsn.AddOpndChain(targetOpnd);
615     cgFunc->GetCurBB()->AppendInsn(jmpInsn);
616 }
617 
GetTargetRetOperand(PrimType primType,int32 sReg)618 Operand &X64MPIsel::GetTargetRetOperand(PrimType primType, int32 sReg)
619 {
620     uint32 bitSize = GetPrimTypeBitSize(primType);
621     regno_t retReg = 0;
622     switch (sReg) {
623         case kSregRetval0:
624             retReg = IsPrimitiveFloat(primType) ? x64::V0 : x64::RAX;
625             break;
626         case kSregRetval1:
627             retReg = x64::RDX;
628             break;
629         default:
630             CHECK_FATAL(false, "GetTargetRetOperand: NIY");
631             break;
632     }
633     RegOperand &parmRegOpnd =
634         cgFunc->GetOpndBuilder()->CreatePReg(retReg, bitSize, cgFunc->GetRegTyFromPrimTy(primType));
635     return parmRegOpnd;
636 }
637 
SelectMpy(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)638 Operand *X64MPIsel::SelectMpy(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
639 {
640     PrimType dtype = node.GetPrimType();
641     RegOperand *resOpnd = nullptr;
642     resOpnd = &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(dtype), cgFunc->GetRegTyFromPrimTy(dtype));
643     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, dtype, node.Opnd(0)->GetPrimType());
644     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, dtype, node.Opnd(1)->GetPrimType());
645     SelectMpy(*resOpnd, regOpnd0, regOpnd1, dtype);
646     return resOpnd;
647 }
648 
SelectMpy(Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)649 void X64MPIsel::SelectMpy(Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
650 {
651     uint32 bitSize = GetPrimTypeBitSize(primType);
652     SelectCopy(resOpnd, opnd0, primType);
653     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType);
654     if (IsSignedInteger(primType) || IsUnsignedInteger(primType)) {
655         X64MOP_t mOp = (bitSize == k64BitSize)   ? x64::MOP_imulq_r_r
656                        : (bitSize == k32BitSize) ? x64::MOP_imull_r_r
657                        : (bitSize == k16BitSize) ? x64::MOP_imulw_r_r
658                                                  : x64::MOP_begin;
659         CHECK_FATAL(mOp != x64::MOP_begin, "NIY mapping");
660         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
661         insn.AddOpndChain(regOpnd1).AddOpndChain(resOpnd);
662         cgFunc->GetCurBB()->AppendInsn(insn);
663     } else if (IsPrimitiveFloat(primType)) {
664         X64MOP_t mOp = (bitSize == k64BitSize)   ? x64::MOP_mulfd_r_r
665                        : (bitSize == k32BitSize) ? x64::MOP_mulfs_r_r
666                                                  : x64::MOP_begin;
667         CHECK_FATAL(mOp != x64::MOP_begin, "NIY mapping");
668         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
669         insn.AddOpndChain(regOpnd1).AddOpndChain(resOpnd);
670         cgFunc->GetCurBB()->AppendInsn(insn);
671     }
672 }
673 
674 /*
675  *  Dividend(EDX:EAX) / Divisor(reg/mem32) = Quotient(EAX)     Remainder(EDX)
676  *  IDIV instruction perform signed division of EDX:EAX by the contents of 32-bit register or memory location and
677  *  store the quotient in EAX and the remainder in EDX.
678  *  The instruction truncates non-integral results towards 0. The sign of the remainder is always the same as the sign
679  *  of the dividend, and the absolute value of the remainder is less than the absolute value of the divisor.
680  *  An overflow generates a #DE (divide error) exception, rather than setting the OF flag.
681  *  To avoid overflow problems, precede this instruction with a CDQ instruction to sign-extend the dividend Divisor.
682  *  CDQ Sign-extend EAX into EDX:EAX. This action helps avoid overflow problems in signed number arithmetic.
683  */
SelectDiv(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)684 Operand *X64MPIsel::SelectDiv(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
685 {
686     PrimType primType = node.GetPrimType();
687     Operand *resOpnd = nullptr;
688     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
689     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
690     resOpnd = SelectDivRem(regOpnd0, regOpnd1, primType, node.GetOpCode());
691     return resOpnd;
692 }
693 
SelectRem(BinaryNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)694 Operand *X64MPIsel::SelectRem(BinaryNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
695 {
696     PrimType primType = node.GetPrimType();
697     Operand *resOpnd = nullptr;
698     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primType, node.Opnd(0)->GetPrimType());
699     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primType, node.Opnd(1)->GetPrimType());
700     resOpnd = SelectDivRem(regOpnd0, regOpnd1, primType, node.GetOpCode());
701     return resOpnd;
702 }
703 
SelectDivRem(RegOperand & opnd0,RegOperand & opnd1,PrimType primType,Opcode opcode)704 Operand *X64MPIsel::SelectDivRem(RegOperand &opnd0, RegOperand &opnd1, PrimType primType, Opcode opcode)
705 {
706     DEBUG_ASSERT(opcode == OP_div || opcode == OP_rem, "unsupported opcode");
707     if (IsSignedInteger(primType) || IsUnsignedInteger(primType)) {
708         uint32 bitSize = GetPrimTypeBitSize(primType);
709         /* copy dividend to eax */
710         RegOperand &raxOpnd =
711             cgFunc->GetOpndBuilder()->CreatePReg(x64::RAX, bitSize, cgFunc->GetRegTyFromPrimTy(primType));
712         SelectCopy(raxOpnd, opnd0, primType);
713 
714         RegOperand &rdxOpnd =
715             cgFunc->GetOpndBuilder()->CreatePReg(x64::RDX, bitSize, cgFunc->GetRegTyFromPrimTy(primType));
716         bool isSigned = IsSignedInteger(primType);
717         if (isSigned) {
718             /* cdq edx:eax = sign-extend of eax*/
719             X64MOP_t cvtMOp = (bitSize == k64BitSize)   ? x64::MOP_cqo
720                               : (bitSize == k32BitSize) ? x64::MOP_cdq
721                               : (bitSize == k16BitSize) ? x64::MOP_cwd
722                                                         : x64::MOP_begin;
723             CHECK_FATAL(cvtMOp != x64::MOP_begin, "NIY mapping");
724             Insn &cvtInsn = cgFunc->GetInsnBuilder()->BuildInsn(cvtMOp, raxOpnd, rdxOpnd);
725             cgFunc->GetCurBB()->AppendInsn(cvtInsn);
726         } else {
727             /* set edx = 0 */
728             SelectCopy(rdxOpnd, cgFunc->GetOpndBuilder()->CreateImm(bitSize, 0), primType);
729         }
730         /* div */
731         X64MOP_t divMOp = (bitSize == k64BitSize)   ? (isSigned ? x64::MOP_idivq_r : x64::MOP_divq_r)
732                           : (bitSize == k32BitSize) ? (isSigned ? x64::MOP_idivl_r : x64::MOP_divl_r)
733                           : (bitSize == k16BitSize) ? (isSigned ? x64::MOP_idivw_r : x64::MOP_divw_r)
734                                                     : x64::MOP_begin;
735         CHECK_FATAL(divMOp != x64::MOP_begin, "NIY mapping");
736         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(divMOp, opnd1, raxOpnd, rdxOpnd);
737         cgFunc->GetCurBB()->AppendInsn(insn);
738         /* return */
739         RegOperand &resOpnd = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(primType));
740         SelectCopy(resOpnd, ((opcode == OP_div) ? raxOpnd : rdxOpnd), primType);
741         return &resOpnd;
742     } else if (IsPrimitiveFloat(primType)) {
743         uint32 bitSize = GetPrimTypeBitSize(primType);
744         auto &resOpnd = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(primType));
745         SelectCopy(resOpnd, opnd0, primType);
746         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(x64::MOP_divsd_r, opnd1, resOpnd);
747         cgFunc->GetCurBB()->AppendInsn(insn);
748         return &resOpnd;
749     } else {
750         CHECK_FATAL(false, "NIY");
751     }
752 }
753 
SelectLnot(const UnaryNode & node,Operand & opnd0,const BaseNode & parent)754 Operand *X64MPIsel::SelectLnot(const UnaryNode &node, Operand &opnd0, const BaseNode &parent)
755 {
756     PrimType dtype = node.GetPrimType();
757     RegOperand *resOpnd = nullptr;
758     resOpnd = &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(dtype), cgFunc->GetRegTyFromPrimTy(dtype));
759     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, dtype, node.Opnd(0)->GetPrimType());
760     ImmOperand &immOpnd = cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(dtype), 0);
761     if (IsPrimitiveFloat(dtype)) {
762         SelectCmpFloatEq(*resOpnd, regOpnd0, immOpnd, dtype, dtype);
763     } else {
764         SelectCmp(regOpnd0, immOpnd, dtype);
765         SelectCmpResult(*resOpnd, OP_eq, dtype, dtype);
766     }
767     return resOpnd;
768 }
769 
770 /*
771  * unorded   ZF, PF, CF  ==> 1,1,1
772  * above     ZF, PF, CF  ==> 0,0,0
773  * below     ZF, PF, CF  ==> 0,0,1
774  * equal     ZF, PF, CF  ==> 1,0,0
775  *
776  * To distinguish between less than(only check whether CF = 1 or not) and unorderd(CF=1),
777  * So ** lt/le in float is replaced by judging gt/ge and swaping operands **
778  *
779  * float eq using cmpeqsd, same with llvm
780  */
SelectCmpOp(CompareNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)781 Operand *X64MPIsel::SelectCmpOp(CompareNode &node, Operand &opnd0, Operand &opnd1, const BaseNode &parent)
782 {
783     PrimType dtype = node.GetPrimType();
784     PrimType primOpndType = node.GetOpndType();
785     RegOperand *resOpnd = nullptr;
786     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, primOpndType, node.Opnd(0)->GetPrimType());
787     RegOperand &regOpnd1 = SelectCopy2Reg(opnd1, primOpndType, node.Opnd(1)->GetPrimType());
788     resOpnd = &cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(dtype), cgFunc->GetRegTyFromPrimTy(dtype));
789     auto nodeOp = node.GetOpCode();
790     Opcode parentOp = parent.GetOpCode();
791     bool isFloat = IsPrimitiveFloat(primOpndType);
792     bool isJump = (parentOp == OP_brfalse || parentOp == OP_brtrue);
793     // float eq
794     if (isFloat && (nodeOp == maple::OP_eq) && (!isJump)) {
795         SelectCmpFloatEq(*resOpnd, regOpnd0, regOpnd1, dtype, primOpndType);
796         return resOpnd;
797     }
798 
799     bool isSwap = (isFloat && (nodeOp == maple::OP_le || nodeOp == maple::OP_lt) && (parentOp != OP_brfalse));
800     SelectCmp(regOpnd0, regOpnd1, primOpndType, isSwap);
801     if (isJump) {
802         return resOpnd;
803     }
804     SelectCmpResult(*resOpnd, nodeOp, dtype, primOpndType);
805     return resOpnd;
806 }
807 
SelectCmp(Operand & opnd0,Operand & opnd1,PrimType primType,bool isSwap)808 void X64MPIsel::SelectCmp(Operand &opnd0, Operand &opnd1, PrimType primType, bool isSwap)
809 {
810     x64::X64MOP_t cmpMOp = x64::MOP_begin;
811     if (IsPrimitiveInteger(primType)) {
812         cmpMOp = GetCmpMop(opnd0.GetKind(), opnd1.GetKind(), primType);
813     } else if (IsPrimitiveFloat(primType)) {
814         cmpMOp = x64::MOP_ucomisd_r_r;
815     } else {
816         CHECK_FATAL(false, "NIY");
817     }
818     DEBUG_ASSERT(cmpMOp != x64::MOP_begin, "unsupported mOp");
819     Insn &cmpInsn = (cgFunc->GetInsnBuilder()->BuildInsn(cmpMOp, X64CG::kMd[cmpMOp]));
820     if (isSwap) {
821         cmpInsn.AddOpndChain(opnd0).AddOpndChain(opnd1);
822     } else {
823         cmpInsn.AddOpndChain(opnd1).AddOpndChain(opnd0);
824     }
825     cgFunc->GetCurBB()->AppendInsn(cmpInsn);
826 }
827 
SelectCmpFloatEq(RegOperand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primResType,PrimType primOpndType)828 void X64MPIsel::SelectCmpFloatEq(RegOperand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primResType,
829                                  PrimType primOpndType)
830 {
831     /* float eq using cmpeqsd is same with llvm */
832     x64::X64MOP_t eqMOp = x64::MOP_cmpeqsd_r_r;
833     Insn &setInsn = cgFunc->GetInsnBuilder()->BuildInsn(eqMOp, X64CG::kMd[eqMOp]);
834 
835     auto &regOpnd1 = cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(primOpndType),
836                                                           cgFunc->GetRegTyFromPrimTy(primOpndType));
837     SelectCopy(regOpnd1, opnd1, primOpndType);
838     /* CMPEQSD xmm1, xmm2  =>  CMPSD xmm1, xmm2, 0 */
839     setInsn.AddOpndChain(opnd0).AddOpndChain(regOpnd1);
840     cgFunc->GetCurBB()->AppendInsn(setInsn);
841 
842     /* set result -> u64/u32 */
843     auto tmpResType = (primOpndType == maple::PTY_f64) ? PTY_u64 : PTY_u32;
844     RegOperand &tmpResOpnd =
845         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(tmpResType), cgFunc->GetRegTyFromPrimTy(tmpResType));
846     SelectRetypeFloat(tmpResOpnd, regOpnd1, tmpResType, primOpndType);
847     /* cvt u64/u32 -> primType */
848     SelectIntCvt(resOpnd, tmpResOpnd, primResType, tmpResType);
849 }
850 
SelectCmpResult(RegOperand & resOpnd,Opcode opCode,PrimType primType,PrimType primOpndType)851 void X64MPIsel::SelectCmpResult(RegOperand &resOpnd, Opcode opCode, PrimType primType, PrimType primOpndType)
852 {
853     bool isFloat = IsPrimitiveFloat(primOpndType);
854     bool isSigned = (!IsPrimitiveUnsigned(primOpndType) && !IsPrimitiveFloat(primOpndType));
855     /* set result -> u8 */
856     RegOperand &tmpResOpnd = cgFunc->GetOpndBuilder()->CreateVReg(k8BitSize, cgFunc->GetRegTyFromPrimTy(PTY_u8));
857     x64::X64MOP_t setMOp = GetSetCCMop(opCode, tmpResOpnd.GetKind(), isSigned, isFloat);
858     DEBUG_ASSERT(setMOp != x64::MOP_begin, "unsupported mOp");
859     Insn &setInsn = cgFunc->GetInsnBuilder()->BuildInsn(setMOp, X64CG::kMd[setMOp]);
860     setInsn.AddOpndChain(tmpResOpnd);
861     cgFunc->GetCurBB()->AppendInsn(setInsn);
862     /* cvt u8 -> primType */
863     SelectIntCvt(resOpnd, tmpResOpnd, primType, PTY_u8);
864 }
865 
SelectSelect(Operand & resOpnd,Operand & trueOpnd,Operand & falseOpnd,PrimType primType,Opcode cmpOpcode,PrimType cmpPrimType)866 void X64MPIsel::SelectSelect(Operand &resOpnd, Operand &trueOpnd, Operand &falseOpnd, PrimType primType,
867                              Opcode cmpOpcode, PrimType cmpPrimType)
868 {
869     CHECK_FATAL(!IsPrimitiveFloat(primType), "NIY");
870     bool isSigned = !IsPrimitiveUnsigned(primType);
871     uint32 bitSize = GetPrimTypeBitSize(primType);
872     if (bitSize == k8BitSize) {
873         /* cmov unsupported 8bit, cvt to 32bit */
874         PrimType cvtType = isSigned ? PTY_i32 : PTY_u32;
875         RegOperand &tmpResOpnd = cgFunc->GetOpndBuilder()->CreateVReg(k32BitSize, kRegTyInt);
876         Operand &tmpTrueOpnd = SelectCopy2Reg(trueOpnd, cvtType, primType);
877         Operand &tmpFalseOpnd = SelectCopy2Reg(falseOpnd, cvtType, primType);
878         SelectSelect(tmpResOpnd, tmpTrueOpnd, tmpFalseOpnd, cvtType, cmpOpcode, cmpPrimType);
879         SelectCopy(resOpnd, tmpResOpnd, primType, cvtType);
880         return;
881     }
882     RegOperand &tmpOpnd = SelectCopy2Reg(trueOpnd, primType);
883     SelectCopy(resOpnd, falseOpnd, primType);
884     x64::X64MOP_t cmovMop = GetCMovCCMop(cmpOpcode, bitSize, !IsPrimitiveUnsigned(cmpPrimType));
885     DEBUG_ASSERT(cmovMop != x64::MOP_begin, "unsupported mOp");
886     Insn &comvInsn = cgFunc->GetInsnBuilder()->BuildInsn(cmovMop, X64CG::kMd[cmovMop]);
887     comvInsn.AddOpndChain(tmpOpnd).AddOpndChain(resOpnd);
888     cgFunc->GetCurBB()->AppendInsn(comvInsn);
889 }
890 
SelectMinOrMax(bool isMin,Operand & resOpnd,Operand & opnd0,Operand & opnd1,PrimType primType)891 void X64MPIsel::SelectMinOrMax(bool isMin, Operand &resOpnd, Operand &opnd0, Operand &opnd1, PrimType primType)
892 {
893     if (IsPrimitiveInteger(primType)) {
894         SelectCmp(opnd0, opnd1, primType);
895         Opcode cmpOpcode = isMin ? OP_lt : OP_gt;
896         SelectSelect(resOpnd, opnd0, opnd1, primType, cmpOpcode, primType);
897     } else {
898         // float lt/le need to swap operands, and using seta
899         CHECK_FATAL(false, "NIY type max or min");
900     }
901 }
902 
SelectCctz(IntrinsicopNode & node,Operand & opnd0,const BaseNode & parent)903 Operand *X64MPIsel::SelectCctz(IntrinsicopNode &node, Operand &opnd0, const BaseNode &parent)
904 {
905     CHECK_FATAL(opnd0.IsImmediate() || opnd0.IsRegister(), "unhandled operand type here!");
906     PrimType origPrimType = node.Opnd(0)->GetPrimType();
907     RegOperand &opnd = SelectCopy2Reg(opnd0, origPrimType);
908 
909     MOperator mopBsf = x64::MOP_bsfl_r_r;
910     Insn &bsfInsn = cgFunc->GetInsnBuilder()->BuildInsn(mopBsf, X64CG::kMd[mopBsf]);
911     bsfInsn.AddOpndChain(opnd).AddOpndChain(opnd);
912     cgFunc->GetCurBB()->AppendInsn(bsfInsn);
913 
914     PrimType retType = node.GetPrimType();
915     RegOperand &destReg =
916         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(retType), cgFunc->GetRegTyFromPrimTy(retType));
917     // ctz i32 (u32) => cvt u32 -> i32
918     // ctz i32 (u64) => cvt u64 -> i32
919     SelectIntCvt(destReg, opnd, retType, origPrimType);
920     return &destReg;
921 }
922 
SelectCclz(IntrinsicopNode & node,Operand & opnd0,const BaseNode & parent)923 Operand *X64MPIsel::SelectCclz(IntrinsicopNode &node, Operand &opnd0, const BaseNode &parent)
924 {
925     CHECK_FATAL(opnd0.IsImmediate() || opnd0.IsRegister(), "unhandled operand type here!");
926     CHECK_FATAL(node.GetIntrinsic() == INTRN_C_clz32, "only support clz32");
927     PrimType origPrimType = node.Opnd(0)->GetPrimType();
928     RegOperand &opnd = SelectCopy2Reg(opnd0, origPrimType);
929     // bsr opnd tmp2
930     ImmOperand &imm =
931         cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(origPrimType), -1);
932     RegOperand &tmp1 = SelectCopy2Reg(imm, origPrimType);
933     RegOperand &tmp2 =
934         cgFunc->GetOpndBuilder()->CreateVReg(
935             GetPrimTypeBitSize(origPrimType), cgFunc->GetRegTyFromPrimTy(origPrimType));
936     MOperator mopBsr = x64::MOP_bsrl_r_r;
937     Insn &bsrInsn = cgFunc->GetInsnBuilder()->BuildInsn(mopBsr, X64CG::kMd[mopBsr]);
938     bsrInsn.AddOpndChain(opnd).AddOpndChain(tmp2);
939     cgFunc->GetCurBB()->AppendInsn(bsrInsn);
940     // cmove -1, tmp2
941     MOperator mopComv = x64::MOP_cmovel_r_r;
942     Insn &cmovInsn = cgFunc->GetInsnBuilder()->BuildInsn(mopComv, X64CG::kMd[mopComv]);
943     cmovInsn.AddOpndChain(tmp1).AddOpndChain(tmp2);
944     cgFunc->GetCurBB()->AppendInsn(cmovInsn);
945     // neg tmp2
946     MOperator mopNeg = x64::MOP_negl_r;
947     Insn &negInsn = cgFunc->GetInsnBuilder()->BuildInsn(mopNeg, X64CG::kMd[mopNeg]);
948     negInsn.AddOpndChain(tmp2);
949     cgFunc->GetCurBB()->AppendInsn(negInsn);
950     // add res 31 tmp2
951     ImmOperand &imm2 =
952         cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeBitSize(origPrimType), k32BitSize - 1);
953     RegOperand &tmp3 =
954         cgFunc->GetOpndBuilder()->CreateVReg(
955             GetPrimTypeBitSize(origPrimType), cgFunc->GetRegTyFromPrimTy(origPrimType));
956     SelectAdd(tmp3, imm2, tmp2, origPrimType);
957     PrimType retType = node.GetPrimType();
958     RegOperand &destReg =
959         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(retType), cgFunc->GetRegTyFromPrimTy(retType));
960     SelectIntCvt(destReg, tmp3, retType, origPrimType);
961     return &destReg;
962 }
SelectHeapConstant(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)963 RegOperand &X64MPIsel::SelectHeapConstant(IntrinsicopNode &node, Operand &opnd0,
964                                           Operand &opnd1, const BaseNode &parent)
965 {
966     PrimType retType = node.GetPrimType();
967     RegOperand &destReg =
968         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(retType), cgFunc->GetRegTyFromPrimTy(retType));
969     MOperator mOp = x64::MOP_heap_const;
970     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
971     insn.AddOpndChain(destReg).AddOpndChain(opnd0).AddOpndChain(opnd1);
972     cgFunc->GetCurBB()->AppendInsn(insn);
973     return destReg;
974 }
975 
SelectTaggedIsHeapObject(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,const BaseNode & parent)976 RegOperand &X64MPIsel::SelectTaggedIsHeapObject(IntrinsicopNode &node, Operand &opnd0,
977                                                 Operand &opnd1, const BaseNode &parent)
978 {
979     RegOperand &destReg = cgFunc->GetOpndBuilder()->CreateVReg(k8BitSize, kRegTyInt);
980     if (opnd0.IsImmediate()) {
981         uint64 value = static_cast<uint64>(static_cast<ImmOperand &>(opnd0).GetValue());
982         uint64 heapObjectMask = static_cast<uint64_t>(static_cast<ImmOperand&>(opnd1).GetValue());
983         MOperator mOp = x64::MOP_movb_i_r;
984         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
985         int8 retValue = static_cast<int64>(value & heapObjectMask) == 0;
986         ImmOperand &imm0 = cgFunc->GetOpndBuilder()->CreateImm(GetPrimTypeActualBitSize(PTY_i8), retValue);
987         insn.AddOpndChain(imm0).AddOpndChain(destReg);
988         cgFunc->GetCurBB()->AppendInsn(insn);
989     } else {
990         RegOperand &tmpReg = cgFunc->GetOpndBuilder()->CreateVReg(k64BitSize, kRegTyInt);
991         MOperator mopMov = x64::MOP_movabs_i_r;
992         Insn &movInsn = cgFunc->GetInsnBuilder()->BuildInsn(mopMov, X64CG::kMd[mopMov]);
993         movInsn.AddOpndChain(opnd1).AddOpndChain(tmpReg);
994         cgFunc->GetCurBB()->AppendInsn(movInsn);
995         MOperator mOp = x64::MOP_tagged_is_heapobject;
996         Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
997         insn.AddOpndChain(destReg).AddOpndChain(tmpReg).AddOpndChain(opnd0);
998         cgFunc->GetCurBB()->AppendInsn(insn);
999     }
1000     return destReg;
1001 }
1002 
SelectIsStableElements(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,Operand & opnd2,const BaseNode & parent)1003 RegOperand &X64MPIsel::SelectIsStableElements(IntrinsicopNode &node, Operand &opnd0, Operand &opnd1,
1004                                               Operand &opnd2, const BaseNode &parent)
1005 {
1006     RegOperand &destReg = cgFunc->GetOpndBuilder()->CreateVReg(k32BitSize, kRegTyInt);
1007     MOperator mOp = x64::MOP_is_stable_elements;
1008     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1009     insn.AddOpndChain(destReg).AddOpndChain(opnd0).AddOpndChain(opnd1).AddOpndChain(opnd2);
1010     cgFunc->GetCurBB()->AppendInsn(insn);
1011     return destReg;
1012 }
1013 
SelectHasPendingException(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,Operand & opnd2,const BaseNode & parent)1014 RegOperand &X64MPIsel::SelectHasPendingException(
1015     IntrinsicopNode &node, Operand &opnd0, Operand &opnd1, Operand &opnd2, const BaseNode &parent)
1016 {
1017     RegOperand &destReg = cgFunc->GetOpndBuilder()->CreateVReg(k8BitSize, kRegTyInt);
1018     MOperator mOp = x64::MOP_has_pending_exception;
1019     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1020     insn.AddOpndChain(destReg).AddOpndChain(opnd0).AddOpndChain(opnd1).AddOpndChain(opnd2);
1021     cgFunc->GetCurBB()->AppendInsn(insn);
1022     return destReg;
1023 }
1024 
SelectGetHeapConstantTable(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,Operand & opnd2,const BaseNode & parent)1025 RegOperand &X64MPIsel::SelectGetHeapConstantTable(IntrinsicopNode &node, Operand &opnd0,
1026     Operand &opnd1, Operand &opnd2, const BaseNode &parent)
1027 {
1028     PrimType retType = node.GetPrimType();
1029     RegOperand &destReg =
1030         cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(retType), cgFunc->GetRegTyFromPrimTy(retType));
1031     MOperator mOp = x64::MOP_get_heap_const_table;
1032     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1033     insn.AddOpndChain(destReg).AddOpndChain(opnd0).AddOpndChain(opnd1).AddOpndChain(opnd2);
1034     cgFunc->GetCurBB()->AppendInsn(insn);
1035     return destReg;
1036 }
1037 
SelectTaggedObjectIsString(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,Operand & opnd2,Operand & opnd3,Operand & opnd4,const BaseNode & parent)1038 RegOperand &X64MPIsel::SelectTaggedObjectIsString(IntrinsicopNode &node, Operand &opnd0,
1039     Operand &opnd1, Operand &opnd2, Operand &opnd3, Operand &opnd4, const BaseNode &parent)
1040 {
1041     RegOperand &dstReg = cgFunc->GetOpndBuilder()->CreateVReg(k8BitSize, kRegTyInt);
1042     RegOperand &tmpReg1 = cgFunc->GetOpndBuilder()->CreateVReg(k32BitSize, kRegTyInt);
1043     RegOperand &tmpReg2 = cgFunc->GetOpndBuilder()->CreateVReg(k64BitSize, kRegTyInt);
1044     MOperator mOp = x64::MOP_tagged_object_is_string;
1045     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1046     insn.AddOpndChain(dstReg).AddOpndChain(opnd0).AddOpndChain(opnd1).AddOpndChain(opnd2).AddOpndChain(opnd3).
1047         AddOpndChain(opnd4).AddOpndChain(tmpReg1).AddOpndChain(tmpReg2);
1048     cgFunc->GetCurBB()->AppendInsn(insn);
1049     return dstReg;
1050 }
1051 
SelectIsCOWArray(IntrinsicopNode & node,Operand & opnd0,Operand & opnd1,Operand & opnd2,Operand & opnd3,Operand & opnd4,Operand & opnd5,const BaseNode & parent)1052 RegOperand &X64MPIsel::SelectIsCOWArray(IntrinsicopNode &node, Operand &opnd0,
1053     Operand &opnd1, Operand &opnd2, Operand &opnd3, Operand &opnd4, Operand &opnd5, const BaseNode &parent)
1054 {
1055     RegOperand &dstReg = cgFunc->GetOpndBuilder()->CreateVReg(k8BitSize, kRegTyInt);
1056     RegOperand &tmpReg1 = cgFunc->GetOpndBuilder()->CreateVReg(k32BitSize, kRegTyInt);
1057     RegOperand &tmpReg2 = cgFunc->GetOpndBuilder()->CreateVReg(k64BitSize, kRegTyInt);
1058     MOperator mOp = x64::MOP_is_cow_array;
1059     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1060     insn.AddOpndChain(dstReg).AddOpndChain(opnd0).AddOpndChain(opnd1).AddOpndChain(opnd2).AddOpndChain(opnd3).
1061         AddOpndChain(opnd4).AddOpndChain(opnd5).AddOpndChain(tmpReg1).AddOpndChain(tmpReg2);
1062     cgFunc->GetCurBB()->AppendInsn(insn);
1063     return dstReg;
1064 }
1065 
GetTargetBasicPointer(PrimType primType)1066 RegOperand &X64MPIsel::GetTargetBasicPointer(PrimType primType)
1067 {
1068     return cgFunc->GetOpndBuilder()->CreatePReg(x64::RBP, GetPrimTypeBitSize(primType),
1069                                                 cgFunc->GetRegTyFromPrimTy(primType));
1070 }
1071 
SelectRetypeFloat(RegOperand & resOpnd,Operand & opnd0,PrimType toType,PrimType fromType)1072 void X64MPIsel::SelectRetypeFloat(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType)
1073 {
1074     uint32 fromSize = GetPrimTypeBitSize(fromType);
1075     [[maybe_unused]] uint32 toSize = GetPrimTypeBitSize(toType);
1076     DEBUG_ASSERT(fromSize == toSize, "retype bit widith doesn' match");
1077     RegOperand &regOpnd0 = SelectCopy2Reg(opnd0, fromType);
1078     MOperator mOp = x64::MOP_begin;
1079     if (fromSize == k32BitSize) {
1080         mOp = IsPrimitiveFloat(fromType) ? x64::MOP_movd_fr_r : x64::MOP_movd_r_fr;
1081     } else if (fromSize == k64BitSize) {
1082         mOp = IsPrimitiveFloat(fromType) ? x64::MOP_movq_fr_r : x64::MOP_movq_r_fr;
1083     } else {
1084         CHECK_FATAL(false, "niy");
1085     }
1086     CHECK_FATAL(mOp != x64::MOP_begin, "NIY");
1087     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1088     (void)insn.AddOpndChain(regOpnd0).AddOpndChain(resOpnd);
1089     cgFunc->GetCurBB()->AppendInsn(insn);
1090     return;
1091 }
1092 
SelectSqrt(UnaryNode & node,Operand & src,const BaseNode & parent)1093 Operand *X64MPIsel::SelectSqrt(UnaryNode &node, Operand &src, const BaseNode &parent)
1094 {
1095     PrimType dtype = node.GetPrimType();
1096     if (!IsPrimitiveFloat(dtype)) {
1097         DEBUG_ASSERT(false, "should be float type");
1098         return nullptr;
1099     }
1100     auto bitSize = GetPrimTypeBitSize(dtype);
1101     MOperator mOp = x64::MOP_begin;
1102     if (bitSize == k64BitSize) {
1103         mOp = MOP_sqrtd_r_r;
1104     } else if (bitSize == k32BitSize) {
1105         mOp = MOP_sqrts_r_r;
1106     } else {
1107         CHECK_FATAL(false, "niy");
1108     }
1109     RegOperand &regOpnd0 = SelectCopy2Reg(src, dtype);
1110     Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, X64CG::kMd[mOp]);
1111     Operand &retReg = cgFunc->GetOpndBuilder()->CreateVReg(bitSize, cgFunc->GetRegTyFromPrimTy(dtype));
1112 
1113     (void)insn.AddOpndChain(regOpnd0).AddOpndChain(retReg);
1114     cgFunc->GetCurBB()->AppendInsn(insn);
1115     return &retReg;
1116 }
1117 }  // namespace maplebe
1118