1 | //=- LoongArchISelLowering.h - LoongArch DAG Lowering Interface -*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines the interfaces that LoongArch uses to lower LLVM code into |
10 | // a selection DAG. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_LIB_TARGET_LOONGARCH_LOONGARCHISELLOWERING_H |
15 | #define LLVM_LIB_TARGET_LOONGARCH_LOONGARCHISELLOWERING_H |
16 | |
17 | #include "LoongArch.h" |
18 | #include "llvm/CodeGen/CallingConvLower.h" |
19 | #include "llvm/CodeGen/SelectionDAG.h" |
20 | #include "llvm/CodeGen/TargetLowering.h" |
21 | |
22 | namespace llvm { |
23 | class LoongArchSubtarget; |
24 | namespace LoongArchISD { |
25 | enum NodeType : unsigned { |
26 | FIRST_NUMBER = ISD::BUILTIN_OP_END, |
27 | |
28 | // TODO: add more LoongArchISDs |
29 | CALL, |
30 | CALL_MEDIUM, |
31 | CALL_LARGE, |
32 | RET, |
33 | TAIL, |
34 | TAIL_MEDIUM, |
35 | TAIL_LARGE, |
36 | |
37 | // Select |
38 | SELECT_CC, |
39 | |
40 | // 32-bit shifts, directly matching the semantics of the named LoongArch |
41 | // instructions. |
42 | SLL_W, |
43 | SRA_W, |
44 | SRL_W, |
45 | |
46 | ROTL_W, |
47 | ROTR_W, |
48 | |
49 | // unsigned 32-bit integer division |
50 | DIV_W, |
51 | MOD_W, |
52 | DIV_WU, |
53 | MOD_WU, |
54 | |
55 | // FPR<->GPR transfer operations |
56 | MOVGR2FR_W_LA64, |
57 | MOVFR2GR_S_LA64, |
58 | MOVFCSR2GR, |
59 | MOVGR2FCSR, |
60 | |
61 | FTINT, |
62 | |
63 | // Build and split F64 pair |
64 | BUILD_PAIR_F64, |
65 | SPLIT_PAIR_F64, |
66 | |
67 | // Bit counting operations |
68 | CLZ_W, |
69 | CTZ_W, |
70 | |
71 | BSTRINS, |
72 | BSTRPICK, |
73 | |
74 | // Byte-swapping and bit-reversal |
75 | REVB_2H, |
76 | REVB_2W, |
77 | BITREV_4B, |
78 | BITREV_8B, |
79 | BITREV_W, |
80 | |
81 | // Intrinsic operations start ============================================ |
82 | BREAK, |
83 | CACOP_D, |
84 | CACOP_W, |
85 | DBAR, |
86 | IBAR, |
87 | SYSCALL, |
88 | |
89 | // CRC check operations |
90 | CRC_W_B_W, |
91 | CRC_W_H_W, |
92 | CRC_W_W_W, |
93 | CRC_W_D_W, |
94 | CRCC_W_B_W, |
95 | CRCC_W_H_W, |
96 | CRCC_W_W_W, |
97 | CRCC_W_D_W, |
98 | |
99 | CSRRD, |
100 | |
101 | // Write new value to CSR and return old value. |
102 | // Operand 0: A chain pointer. |
103 | // Operand 1: The new value to write. |
104 | // Operand 2: The address of the required CSR. |
105 | // Result 0: The old value of the CSR. |
106 | // Result 1: The new chain pointer. |
107 | CSRWR, |
108 | |
109 | // Similar to CSRWR but with a write mask. |
110 | // Operand 0: A chain pointer. |
111 | // Operand 1: The new value to write. |
112 | // Operand 2: The write mask. |
113 | // Operand 3: The address of the required CSR. |
114 | // Result 0: The old value of the CSR. |
115 | // Result 1: The new chain pointer. |
116 | CSRXCHG, |
117 | |
118 | // IOCSR access operations |
119 | IOCSRRD_B, |
120 | IOCSRRD_W, |
121 | IOCSRRD_H, |
122 | IOCSRRD_D, |
123 | IOCSRWR_B, |
124 | IOCSRWR_H, |
125 | IOCSRWR_W, |
126 | IOCSRWR_D, |
127 | |
128 | // Read CPU configuration information operation |
129 | CPUCFG, |
130 | |
131 | // Vector Shuffle |
132 | VREPLVE, |
133 | VSHUF, |
134 | VPICKEV, |
135 | VPICKOD, |
136 | VPACKEV, |
137 | VPACKOD, |
138 | VILVL, |
139 | VILVH, |
140 | VSHUF4I, |
141 | VREPLVEI, |
142 | VREPLGR2VR, |
143 | XVPERMI, |
144 | |
145 | // Extended vector element extraction |
146 | VPICK_SEXT_ELT, |
147 | VPICK_ZEXT_ELT, |
148 | |
149 | // Vector comparisons |
150 | VALL_ZERO, |
151 | VANY_ZERO, |
152 | VALL_NONZERO, |
153 | VANY_NONZERO, |
154 | |
155 | // Floating point approximate reciprocal operation |
156 | FRECIPE, |
157 | FRSQRTE, |
158 | |
159 | // Vector logicial left / right shift by immediate |
160 | VSLLI, |
161 | VSRLI, |
162 | |
163 | // Vector byte logicial left / right shift |
164 | VBSLL, |
165 | VBSRL, |
166 | |
167 | // Scalar load broadcast to vector |
168 | VLDREPL, |
169 | |
170 | // Vector mask set by condition |
171 | VMSKLTZ, |
172 | VMSKGEZ, |
173 | VMSKEQZ, |
174 | VMSKNEZ, |
175 | XVMSKLTZ, |
176 | XVMSKGEZ, |
177 | XVMSKEQZ, |
178 | XVMSKNEZ, |
179 | |
180 | // Intrinsic operations end ============================================= |
181 | }; |
182 | } // end namespace LoongArchISD |
183 | |
184 | class LoongArchTargetLowering : public TargetLowering { |
185 | const LoongArchSubtarget &Subtarget; |
186 | |
187 | public: |
188 | explicit LoongArchTargetLowering(const TargetMachine &TM, |
189 | const LoongArchSubtarget &STI); |
190 | |
191 | const LoongArchSubtarget &getSubtarget() const { return Subtarget; } |
192 | |
193 | bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; |
194 | |
195 | // Provide custom lowering hooks for some operations. |
196 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; |
197 | void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results, |
198 | SelectionDAG &DAG) const override; |
199 | |
200 | SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; |
201 | |
202 | // This method returns the name of a target specific DAG node. |
203 | const char *getTargetNodeName(unsigned Opcode) const override; |
204 | |
205 | // Lower incoming arguments, copy physregs into vregs. |
206 | SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, |
207 | bool IsVarArg, |
208 | const SmallVectorImpl<ISD::InputArg> &Ins, |
209 | const SDLoc &DL, SelectionDAG &DAG, |
210 | SmallVectorImpl<SDValue> &InVals) const override; |
211 | bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, |
212 | bool IsVarArg, |
213 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
214 | LLVMContext &Context, const Type *RetTy) const override; |
215 | SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, |
216 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
217 | const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, |
218 | SelectionDAG &DAG) const override; |
219 | SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, |
220 | SmallVectorImpl<SDValue> &InVals) const override; |
221 | bool isCheapToSpeculateCttz(Type *Ty) const override; |
222 | bool isCheapToSpeculateCtlz(Type *Ty) const override; |
223 | bool hasAndNot(SDValue Y) const override; |
224 | TargetLowering::AtomicExpansionKind |
225 | shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const override; |
226 | void emitExpandAtomicRMW(AtomicRMWInst *AI) const override; |
227 | |
228 | Value *emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, |
229 | Value *AlignedAddr, Value *Incr, |
230 | Value *Mask, Value *ShiftAmt, |
231 | AtomicOrdering Ord) const override; |
232 | |
233 | EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, |
234 | EVT VT) const override; |
235 | TargetLowering::AtomicExpansionKind |
236 | shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *CI) const override; |
237 | Value *emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, |
238 | AtomicCmpXchgInst *CI, |
239 | Value *AlignedAddr, Value *CmpVal, |
240 | Value *NewVal, Value *Mask, |
241 | AtomicOrdering Ord) const override; |
242 | |
243 | bool getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, |
244 | MachineFunction &MF, |
245 | unsigned Intrinsic) const override; |
246 | |
247 | bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, |
248 | EVT VT) const override; |
249 | |
250 | Register |
251 | getExceptionPointerRegister(const Constant *PersonalityFn) const override; |
252 | |
253 | Register |
254 | getExceptionSelectorRegister(const Constant *PersonalityFn) const override; |
255 | |
256 | bool isFsqrtCheap(SDValue Operand, SelectionDAG &DAG) const override { |
257 | return true; |
258 | } |
259 | |
260 | SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, |
261 | int &RefinementSteps, bool &UseOneConstNR, |
262 | bool Reciprocal) const override; |
263 | |
264 | SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, int Enabled, |
265 | int &RefinementSteps) const override; |
266 | |
267 | ISD::NodeType getExtendForAtomicOps() const override { |
268 | return ISD::SIGN_EXTEND; |
269 | } |
270 | |
271 | ISD::NodeType getExtendForAtomicCmpSwapArg() const override; |
272 | |
273 | Register getRegisterByName(const char *RegName, LLT VT, |
274 | const MachineFunction &MF) const override; |
275 | bool mayBeEmittedAsTailCall(const CallInst *CI) const override; |
276 | |
277 | bool decomposeMulByConstant(LLVMContext &Context, EVT VT, |
278 | SDValue C) const override; |
279 | |
280 | bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override; |
281 | |
282 | bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, |
283 | unsigned AS, |
284 | Instruction *I = nullptr) const override; |
285 | |
286 | bool isLegalICmpImmediate(int64_t Imm) const override; |
287 | bool isLegalAddImmediate(int64_t Imm) const override; |
288 | bool isZExtFree(SDValue Val, EVT VT2) const override; |
289 | bool isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const override; |
290 | bool signExtendConstant(const ConstantInt *CI) const override; |
291 | |
292 | bool hasAndNotCompare(SDValue Y) const override; |
293 | |
294 | bool convertSelectOfConstantsToMath(EVT VT) const override { return true; } |
295 | |
296 | bool allowsMisalignedMemoryAccesses( |
297 | EVT VT, unsigned AddrSpace = 0, Align Alignment = Align(1), |
298 | MachineMemOperand::Flags Flags = MachineMemOperand::MONone, |
299 | unsigned *Fast = nullptr) const override; |
300 | |
301 | bool isShuffleMaskLegal(ArrayRef<int> Mask, EVT VT) const override { |
302 | if (!VT.isSimple()) |
303 | return false; |
304 | |
305 | // Not for i1 vectors |
306 | if (VT.getSimpleVT().getScalarType() == MVT::i1) |
307 | return false; |
308 | |
309 | return isTypeLegal(VT: VT.getSimpleVT()); |
310 | } |
311 | bool shouldConsiderGEPOffsetSplit() const override { return true; } |
312 | bool shouldSignExtendTypeInLibCall(Type *Ty, bool IsSigned) const override; |
313 | bool shouldExtendTypeInLibCall(EVT Type) const override; |
314 | |
315 | bool shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, |
316 | Align &PrefAlign) const override; |
317 | |
318 | bool isFPImmVLDILegal(const APFloat &Imm, EVT VT) const; |
319 | LegalizeTypeAction getPreferredVectorAction(MVT VT) const override; |
320 | |
321 | bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits, |
322 | const APInt &DemandedElts, |
323 | KnownBits &Known, |
324 | TargetLoweringOpt &TLO, |
325 | unsigned Depth) const override; |
326 | |
327 | private: |
328 | /// Target-specific function used to lower LoongArch calling conventions. |
329 | typedef bool LoongArchCCAssignFn(const DataLayout &DL, LoongArchABI::ABI ABI, |
330 | unsigned ValNo, MVT ValVT, |
331 | CCValAssign::LocInfo LocInfo, |
332 | ISD::ArgFlagsTy ArgFlags, CCState &State, |
333 | bool IsFixed, bool IsRet, Type *OrigTy); |
334 | |
335 | void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, |
336 | const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet, |
337 | LoongArchCCAssignFn Fn) const; |
338 | void analyzeOutputArgs(MachineFunction &MF, CCState &CCInfo, |
339 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
340 | bool IsRet, CallLoweringInfo *CLI, |
341 | LoongArchCCAssignFn Fn) const; |
342 | |
343 | template <class NodeTy> |
344 | SDValue getAddr(NodeTy *N, SelectionDAG &DAG, CodeModel::Model M, |
345 | bool IsLocal = true) const; |
346 | SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, |
347 | unsigned Opc, bool UseGOT, bool Large = false) const; |
348 | SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, |
349 | unsigned Opc, bool Large = false) const; |
350 | SDValue getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, |
351 | unsigned Opc, bool Large = false) const; |
352 | SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; |
353 | SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; |
354 | SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const; |
355 | SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; |
356 | SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; |
357 | SDValue lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; |
358 | |
359 | MachineBasicBlock * |
360 | EmitInstrWithCustomInserter(MachineInstr &MI, |
361 | MachineBasicBlock *BB) const override; |
362 | SDValue lowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const; |
363 | SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const; |
364 | SDValue lowerEH_DWARF_CFA(SDValue Op, SelectionDAG &DAG) const; |
365 | SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; |
366 | SDValue lowerBITCAST(SDValue Op, SelectionDAG &DAG) const; |
367 | SDValue lowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; |
368 | SDValue lowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; |
369 | SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; |
370 | SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; |
371 | SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const; |
372 | SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; |
373 | SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; |
374 | SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; |
375 | SDValue lowerWRITE_REGISTER(SDValue Op, SelectionDAG &DAG) const; |
376 | SDValue (SDValue Op, SelectionDAG &DAG) const; |
377 | SDValue lowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const; |
378 | SDValue lowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const; |
379 | SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const; |
380 | SDValue lowerBITREVERSE(SDValue Op, SelectionDAG &DAG) const; |
381 | SDValue lowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG) const; |
382 | SDValue lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const; |
383 | SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; |
384 | SDValue lowerFP_TO_FP16(SDValue Op, SelectionDAG &DAG) const; |
385 | SDValue lowerFP16_TO_FP(SDValue Op, SelectionDAG &DAG) const; |
386 | SDValue lowerFP_TO_BF16(SDValue Op, SelectionDAG &DAG) const; |
387 | SDValue lowerBF16_TO_FP(SDValue Op, SelectionDAG &DAG) const; |
388 | |
389 | bool isFPImmLegal(const APFloat &Imm, EVT VT, |
390 | bool ForCodeSize) const override; |
391 | |
392 | bool shouldInsertFencesForAtomic(const Instruction *I) const override; |
393 | |
394 | ConstraintType getConstraintType(StringRef Constraint) const override; |
395 | |
396 | InlineAsm::ConstraintCode |
397 | getInlineAsmMemConstraint(StringRef ConstraintCode) const override; |
398 | |
399 | std::pair<unsigned, const TargetRegisterClass *> |
400 | getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, |
401 | StringRef Constraint, MVT VT) const override; |
402 | |
403 | void LowerAsmOperandForConstraint(SDValue Op, StringRef Constraint, |
404 | std::vector<SDValue> &Ops, |
405 | SelectionDAG &DAG) const override; |
406 | |
407 | bool isEligibleForTailCallOptimization( |
408 | CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, |
409 | const SmallVectorImpl<CCValAssign> &ArgLocs) const; |
410 | |
411 | bool softPromoteHalfType() const override { return true; } |
412 | |
413 | bool |
414 | splitValueIntoRegisterParts(SelectionDAG &DAG, const SDLoc &DL, SDValue Val, |
415 | SDValue *Parts, unsigned NumParts, MVT PartVT, |
416 | std::optional<CallingConv::ID> CC) const override; |
417 | |
418 | SDValue |
419 | joinRegisterPartsIntoValue(SelectionDAG &DAG, const SDLoc &DL, |
420 | const SDValue *Parts, unsigned NumParts, |
421 | MVT PartVT, EVT ValueVT, |
422 | std::optional<CallingConv::ID> CC) const override; |
423 | |
424 | /// Return the register type for a given MVT, ensuring vectors are treated |
425 | /// as a series of gpr sized integers. |
426 | MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, |
427 | EVT VT) const override; |
428 | |
429 | /// Return the number of registers for a given MVT, ensuring vectors are |
430 | /// treated as a series of gpr sized integers. |
431 | unsigned getNumRegistersForCallingConv(LLVMContext &Context, |
432 | CallingConv::ID CC, |
433 | EVT VT) const override; |
434 | }; |
435 | |
436 | } // end namespace llvm |
437 | |
438 | #endif // LLVM_LIB_TARGET_LOONGARCH_LOONGARCHISELLOWERING_H |
439 | |