| 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 | |