LLVM 17.0.0git
LoongArchISelLowering.cpp
Go to the documentation of this file.
1//=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation ---===//
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
15#include "LoongArch.h"
18#include "LoongArchSubtarget.h"
22#include "llvm/ADT/Statistic.h"
25#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/IntrinsicsLoongArch.h"
27#include "llvm/Support/Debug.h"
30
31using namespace llvm;
32
33#define DEBUG_TYPE "loongarch-isel-lowering"
34
35STATISTIC(NumTailCalls, "Number of tail calls");
36
38 "loongarch-check-zero-division", cl::Hidden,
39 cl::desc("Trap on integer division by zero."),
40 cl::init(false));
41
43 const LoongArchSubtarget &STI)
44 : TargetLowering(TM), Subtarget(STI) {
45
46 MVT GRLenVT = Subtarget.getGRLenVT();
47 // Set up the register classes.
48 addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
49 if (Subtarget.hasBasicF())
50 addRegisterClass(MVT::f32, &LoongArch::FPR32RegClass);
51 if (Subtarget.hasBasicD())
52 addRegisterClass(MVT::f64, &LoongArch::FPR64RegClass);
53
56
57 // TODO: add necessary setOperationAction calls later.
68
71 GRLenVT, Custom);
72
74
76
78 if (Subtarget.is64Bit())
80
85
86 if (Subtarget.is64Bit()) {
101 if (Subtarget.hasBasicF() && !Subtarget.hasBasicD())
103 if (Subtarget.hasBasicF())
105 if (Subtarget.hasBasicD())
107 }
108
109 // LA32 does not have REVB.2W and REVB.D due to the 64-bit operands, and
110 // the narrower REVB.W does not exist. But LA32 does have REVB.2H, so i16
111 // and i32 could still be byte-swapped relatively cheaply.
113 if (Subtarget.is64Bit()) {
115 }
116
117 // Expand bitreverse.i16 with native-width bitrev and shift for now, before
118 // we get to know which of sll and revb.2h is faster.
120 if (Subtarget.is64Bit()) {
123 } else {
130 }
131
132 static const ISD::CondCode FPCCToExpand[] = {
135
136 if (Subtarget.hasBasicF()) {
137 setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
150 }
151 if (Subtarget.hasBasicD()) {
152 setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
167 }
168
170
175 if (!Subtarget.is64Bit())
176 setLibcallName(RTLIB::MUL_I128, nullptr);
177
180 if ((Subtarget.is64Bit() && Subtarget.hasBasicF() &&
181 !Subtarget.hasBasicD())) {
184 }
185
186 // Compute derived properties from the register classes.
188
190
192
194
196
197 // Function alignments.
199
203}
204
206 const GlobalAddressSDNode *GA) const {
207 // In order to maximise the opportunity for common subexpression elimination,
208 // keep a separate ADD node for the global address offset instead of folding
209 // it in the global address node. Later peephole optimisations may choose to
210 // fold it back in when profitable.
211 return false;
212}
213
215 SelectionDAG &DAG) const {
216 switch (Op.getOpcode()) {
218 return lowerEH_DWARF_CFA(Op, DAG);
220 return lowerGlobalAddress(Op, DAG);
222 return lowerGlobalTLSAddress(Op, DAG);
224 return lowerINTRINSIC_WO_CHAIN(Op, DAG);
226 return lowerINTRINSIC_W_CHAIN(Op, DAG);
228 return lowerINTRINSIC_VOID(Op, DAG);
230 return lowerBlockAddress(Op, DAG);
231 case ISD::JumpTable:
232 return lowerJumpTable(Op, DAG);
233 case ISD::SHL_PARTS:
234 return lowerShiftLeftParts(Op, DAG);
235 case ISD::SRA_PARTS:
236 return lowerShiftRightParts(Op, DAG, true);
237 case ISD::SRL_PARTS:
238 return lowerShiftRightParts(Op, DAG, false);
240 return lowerConstantPool(Op, DAG);
241 case ISD::FP_TO_SINT:
242 return lowerFP_TO_SINT(Op, DAG);
243 case ISD::BITCAST:
244 return lowerBITCAST(Op, DAG);
245 case ISD::UINT_TO_FP:
246 return lowerUINT_TO_FP(Op, DAG);
247 case ISD::SINT_TO_FP:
248 return lowerSINT_TO_FP(Op, DAG);
249 case ISD::VASTART:
250 return lowerVASTART(Op, DAG);
251 case ISD::FRAMEADDR:
252 return lowerFRAMEADDR(Op, DAG);
253 case ISD::RETURNADDR:
254 return lowerRETURNADDR(Op, DAG);
256 return lowerWRITE_REGISTER(Op, DAG);
257 }
258 return SDValue();
259}
260
261SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op,
262 SelectionDAG &DAG) const {
263
264 if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) {
265 DAG.getContext()->emitError(
266 "On LA64, only 64-bit registers can be written.");
267 return Op.getOperand(0);
268 }
269
270 if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) {
271 DAG.getContext()->emitError(
272 "On LA32, only 32-bit registers can be written.");
273 return Op.getOperand(0);
274 }
275
276 return Op;
277}
278
279SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op,
280 SelectionDAG &DAG) const {
281 if (!isa<ConstantSDNode>(Op.getOperand(0))) {
282 DAG.getContext()->emitError("argument to '__builtin_frame_address' must "
283 "be a constant integer");
284 return SDValue();
285 }
286
289 Register FrameReg = Subtarget.getRegisterInfo()->getFrameRegister(MF);
290 EVT VT = Op.getValueType();
291 SDLoc DL(Op);
292 SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT);
293 unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
294 int GRLenInBytes = Subtarget.getGRLen() / 8;
295
296 while (Depth--) {
297 int Offset = -(GRLenInBytes * 2);
298 SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr,
300 FrameAddr =
301 DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
302 }
303 return FrameAddr;
304}
305
306SDValue LoongArchTargetLowering::lowerRETURNADDR(SDValue Op,
307 SelectionDAG &DAG) const {
309 return SDValue();
310
311 // Currently only support lowering return address for current frame.
312 if (cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() != 0) {
313 DAG.getContext()->emitError(
314 "return address can only be determined for the current frame");
315 return SDValue();
316 }
317
320 MVT GRLenVT = Subtarget.getGRLenVT();
321
322 // Return the value of the return address register, marking it an implicit
323 // live-in.
324 Register Reg = MF.addLiveIn(Subtarget.getRegisterInfo()->getRARegister(),
325 getRegClassFor(GRLenVT));
326 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, GRLenVT);
327}
328
329SDValue LoongArchTargetLowering::lowerEH_DWARF_CFA(SDValue Op,
330 SelectionDAG &DAG) const {
332 auto Size = Subtarget.getGRLen() / 8;
333 auto FI = MF.getFrameInfo().CreateFixedObject(Size, 0, false);
334 return DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
335}
336
337SDValue LoongArchTargetLowering::lowerVASTART(SDValue Op,
338 SelectionDAG &DAG) const {
341
342 SDLoc DL(Op);
343 SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(),
345
346 // vastart just stores the address of the VarArgsFrameIndex slot into the
347 // memory location argument.
348 const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
349 return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1),
351}
352
353SDValue LoongArchTargetLowering::lowerUINT_TO_FP(SDValue Op,
354 SelectionDAG &DAG) const {
355 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
356 !Subtarget.hasBasicD() && "unexpected target features");
357
358 SDLoc DL(Op);
359 SDValue Op0 = Op.getOperand(0);
360 if (Op0->getOpcode() == ISD::AND) {
361 auto *C = dyn_cast<ConstantSDNode>(Op0.getOperand(1));
362 if (C && C->getZExtValue() < UINT64_C(0xFFFFFFFF))
363 return Op;
364 }
365
366 if (Op0->getOpcode() == LoongArchISD::BSTRPICK &&
367 Op0.getConstantOperandVal(1) < UINT64_C(0X1F) &&
368 Op0.getConstantOperandVal(2) == UINT64_C(0))
369 return Op;
370
371 if (Op0.getOpcode() == ISD::AssertZext &&
372 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLT(MVT::i32))
373 return Op;
374
375 EVT OpVT = Op0.getValueType();
376 EVT RetVT = Op.getValueType();
377 RTLIB::Libcall LC = RTLIB::getUINTTOFP(OpVT, RetVT);
378 MakeLibCallOptions CallOptions;
379 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
380 SDValue Chain = SDValue();
382 std::tie(Result, Chain) =
383 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
384 return Result;
385}
386
387SDValue LoongArchTargetLowering::lowerSINT_TO_FP(SDValue Op,
388 SelectionDAG &DAG) const {
389 assert(Subtarget.is64Bit() && Subtarget.hasBasicF() &&
390 !Subtarget.hasBasicD() && "unexpected target features");
391
392 SDLoc DL(Op);
393 SDValue Op0 = Op.getOperand(0);
394
395 if ((Op0.getOpcode() == ISD::AssertSext ||
397 dyn_cast<VTSDNode>(Op0.getOperand(1))->getVT().bitsLE(MVT::i32))
398 return Op;
399
400 EVT OpVT = Op0.getValueType();
401 EVT RetVT = Op.getValueType();
402 RTLIB::Libcall LC = RTLIB::getSINTTOFP(OpVT, RetVT);
403 MakeLibCallOptions CallOptions;
404 CallOptions.setTypeListBeforeSoften(OpVT, RetVT, true);
405 SDValue Chain = SDValue();
407 std::tie(Result, Chain) =
408 makeLibCall(DAG, LC, Op.getValueType(), Op0, CallOptions, DL, Chain);
409 return Result;
410}
411
412SDValue LoongArchTargetLowering::lowerBITCAST(SDValue Op,
413 SelectionDAG &DAG) const {
414
415 SDLoc DL(Op);
416 SDValue Op0 = Op.getOperand(0);
417
418 if (Op.getValueType() == MVT::f32 && Op0.getValueType() == MVT::i32 &&
419 Subtarget.is64Bit() && Subtarget.hasBasicF()) {
420 SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0);
421 return DAG.getNode(LoongArchISD::MOVGR2FR_W_LA64, DL, MVT::f32, NewOp0);
422 }
423 return Op;
424}
425
426SDValue LoongArchTargetLowering::lowerFP_TO_SINT(SDValue Op,
427 SelectionDAG &DAG) const {
428
429 SDLoc DL(Op);
430
431 if (Op.getValueSizeInBits() > 32 && Subtarget.hasBasicF() &&
432 !Subtarget.hasBasicD()) {
433 SDValue Dst =
434 DAG.getNode(LoongArchISD::FTINT, DL, MVT::f32, Op.getOperand(0));
436 }
437
438 EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits());
439 SDValue Trunc = DAG.getNode(LoongArchISD::FTINT, DL, FPTy, Op.getOperand(0));
440 return DAG.getNode(ISD::BITCAST, DL, Op.getValueType(), Trunc);
441}
442
444 SelectionDAG &DAG, unsigned Flags) {
445 return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
446}
447
449 SelectionDAG &DAG, unsigned Flags) {
450 return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
451 Flags);
452}
453
455 SelectionDAG &DAG, unsigned Flags) {
456 return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(),
457 N->getOffset(), Flags);
458}
459
461 SelectionDAG &DAG, unsigned Flags) {
462 return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags);
463}
464
465template <class NodeTy>
466SDValue LoongArchTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG,
467 bool IsLocal) const {
468 SDLoc DL(N);
469 EVT Ty = getPointerTy(DAG.getDataLayout());
470 SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
471 // TODO: Check CodeModel.
472 if (IsLocal)
473 // This generates the pattern (PseudoLA_PCREL sym), which expands to
474 // (addi.w/d (pcalau12i %pc_hi20(sym)) %pc_lo12(sym)).
475 return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_PCREL, DL, Ty, Addr),
476 0);
477
478 // This generates the pattern (PseudoLA_GOT sym), which expands to (ld.w/d
479 // (pcalau12i %got_pc_hi20(sym)) %got_pc_lo12(sym)).
480 return SDValue(DAG.getMachineNode(LoongArch::PseudoLA_GOT, DL, Ty, Addr), 0);
481}
482
483SDValue LoongArchTargetLowering::lowerBlockAddress(SDValue Op,
484 SelectionDAG &DAG) const {
485 return getAddr(cast<BlockAddressSDNode>(Op), DAG);
486}
487
488SDValue LoongArchTargetLowering::lowerJumpTable(SDValue Op,
489 SelectionDAG &DAG) const {
490 return getAddr(cast<JumpTableSDNode>(Op), DAG);
491}
492
493SDValue LoongArchTargetLowering::lowerConstantPool(SDValue Op,
494 SelectionDAG &DAG) const {
495 return getAddr(cast<ConstantPoolSDNode>(Op), DAG);
496}
497
498SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op,
499 SelectionDAG &DAG) const {
500 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
501 assert(N->getOffset() == 0 && "unexpected offset in global node");
502 return getAddr(N, DAG, N->getGlobal()->isDSOLocal());
503}
504
505SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N,
506 SelectionDAG &DAG,
507 unsigned Opc) const {
508 SDLoc DL(N);
509 EVT Ty = getPointerTy(DAG.getDataLayout());
510 MVT GRLenVT = Subtarget.getGRLenVT();
511
512 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
513 SDValue Offset = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
514
515 // Add the thread pointer.
516 return DAG.getNode(ISD::ADD, DL, Ty, Offset,
517 DAG.getRegister(LoongArch::R2, GRLenVT));
518}
519
520SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
521 SelectionDAG &DAG,
522 unsigned Opc) const {
523 SDLoc DL(N);
524 EVT Ty = getPointerTy(DAG.getDataLayout());
525 IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits());
526
527 // Use a PC-relative addressing mode to access the dynamic GOT address.
528 SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0);
529 SDValue Load = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
530
531 // Prepare argument list to generate call.
533 ArgListEntry Entry;
534 Entry.Node = Load;
535 Entry.Ty = CallTy;
536 Args.push_back(Entry);
537
538 // Setup call to __tls_get_addr.
540 CLI.setDebugLoc(DL)
541 .setChain(DAG.getEntryNode())
542 .setLibCallee(CallingConv::C, CallTy,
543 DAG.getExternalSymbol("__tls_get_addr", Ty),
544 std::move(Args));
545
546 return LowerCallTo(CLI).first;
547}
548
550LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
551 SelectionDAG &DAG) const {
554 report_fatal_error("In GHC calling convention TLS is not supported");
555
556 GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
557 assert(N->getOffset() == 0 && "unexpected offset in global node");
558
560 switch (getTargetMachine().getTLSModel(N->getGlobal())) {
562 // In this model, application code calls the dynamic linker function
563 // __tls_get_addr to locate TLS offsets into the dynamic thread vector at
564 // runtime.
565 Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_GD);
566 break;
568 // Same as GeneralDynamic, except for assembly modifiers and relocation
569 // records.
570 Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LD);
571 break;
573 // This model uses the GOT to resolve TLS offsets.
574 Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_IE);
575 break;
577 // This model is used when static linking as the TLS offsets are resolved
578 // during program linking.
579 Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
580 break;
581 }
582
583 return Addr;
584}
585
587LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
588 SelectionDAG &DAG) const {
589 switch (Op.getConstantOperandVal(0)) {
590 default:
591 return SDValue(); // Don't custom lower most intrinsics.
592 case Intrinsic::thread_pointer: {
593 EVT PtrVT = getPointerTy(DAG.getDataLayout());
594 return DAG.getRegister(LoongArch::R2, PtrVT);
595 }
596 }
597}
598
599// Helper function that emits error message for intrinsics with chain.
601 StringRef ErrorMsg,
602 SelectionDAG &DAG) {
603
604 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
605 ErrorMsg);
606 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)},
607 SDLoc(Op));
608}
609
611LoongArchTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
612 SelectionDAG &DAG) const {
613 SDLoc DL(Op);
614 MVT GRLenVT = Subtarget.getGRLenVT();
615 SDValue Op0 = Op.getOperand(0);
616 std::string Name = Op->getOperationName(0);
617 const StringRef ErrorMsgOOR = "out of range";
618
619 switch (Op.getConstantOperandVal(1)) {
620 default:
621 return Op;
622 case Intrinsic::loongarch_crc_w_b_w:
623 case Intrinsic::loongarch_crc_w_h_w:
624 case Intrinsic::loongarch_crc_w_w_w:
625 case Intrinsic::loongarch_crc_w_d_w:
626 case Intrinsic::loongarch_crcc_w_b_w:
627 case Intrinsic::loongarch_crcc_w_h_w:
628 case Intrinsic::loongarch_crcc_w_w_w:
629 case Intrinsic::loongarch_crcc_w_d_w: {
630 std::string Name = Op->getOperationName(0);
631 DAG.getContext()->emitError(Name + " requires target: loongarch64");
632 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
633 }
634 case Intrinsic::loongarch_csrrd_w:
635 case Intrinsic::loongarch_csrrd_d: {
636 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
637 if (!isUInt<14>(Imm))
638 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
639 return DAG.getMergeValues(
640 {DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
641 DAG.getConstant(Imm, DL, GRLenVT)),
642 Op0},
643 DL);
644 }
645 case Intrinsic::loongarch_csrwr_w:
646 case Intrinsic::loongarch_csrwr_d: {
647 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
648 if (!isUInt<14>(Imm))
649 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
650 return DAG.getMergeValues(
651 {DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0, Op.getOperand(2),
652 DAG.getConstant(Imm, DL, GRLenVT)),
653 Op0},
654 DL);
655 }
656 case Intrinsic::loongarch_csrxchg_w:
657 case Intrinsic::loongarch_csrxchg_d: {
658 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue();
659 if (!isUInt<14>(Imm))
660 return emitIntrinsicWithChainErrorMessage(Op, ErrorMsgOOR, DAG);
661 return DAG.getMergeValues(
662 {DAG.getNode(LoongArchISD::CSRXCHG, DL, GRLenVT, Op0, Op.getOperand(2),
663 Op.getOperand(3), DAG.getConstant(Imm, DL, GRLenVT)),
664 Op0},
665 DL);
666 }
667 case Intrinsic::loongarch_iocsrrd_d: {
668 if (Subtarget.is64Bit())
669 return DAG.getMergeValues(
670 {DAG.getNode(
671 LoongArchISD::IOCSRRD_D, DL, GRLenVT, Op0,
672 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(2))),
673 Op0},
674 DL);
675 else {
676 DAG.getContext()->emitError(
677 "llvm.loongarch.crc.w.d.w requires target: loongarch64");
678 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
679 }
680 }
681#define IOCSRRD_CASE(NAME, NODE) \
682 case Intrinsic::loongarch_##NAME: { \
683 return DAG.getMergeValues( \
684 {DAG.getNode(LoongArchISD::NODE, DL, GRLenVT, Op0, Op.getOperand(2)), \
685 Op0}, \
686 DL); \
687 }
688 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
689 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
690 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
691#undef IOCSRRD_CASE
692 case Intrinsic::loongarch_cpucfg: {
693 return DAG.getMergeValues(
694 {DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0, Op.getOperand(2)),
695 Op0},
696 DL);
697 }
698 case Intrinsic::loongarch_lddir_d: {
699 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
700 if (!isUInt<8>(Imm)) {
701 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
702 "' out of range");
703 return DAG.getMergeValues({DAG.getUNDEF(Op.getValueType()), Op0}, DL);
704 }
705
706 return Op;
707 }
708 case Intrinsic::loongarch_movfcsr2gr: {
709 if (!Subtarget.hasBasicF()) {
710 DAG.getContext()->emitError(
711 "llvm.loongarch.movfcsr2gr expects basic f target feature");
712 return DAG.getMergeValues(
713 {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
714 }
715 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
716 if (!isUInt<2>(Imm)) {
717 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) +
718 "' " + ErrorMsgOOR);
719 return DAG.getMergeValues(
720 {DAG.getUNDEF(Op.getValueType()), Op.getOperand(0)}, SDLoc(Op));
721 }
722 return DAG.getMergeValues(
723 {DAG.getNode(LoongArchISD::MOVFCSR2GR, DL, Op.getValueType(),
724 DAG.getConstant(Imm, DL, GRLenVT)),
725 Op.getOperand(0)},
726 DL);
727 }
728 }
729}
730
731// Helper function that emits error message for intrinsics with void return
732// value.
734 SelectionDAG &DAG) {
735
736 DAG.getContext()->emitError("argument to '" + Op->getOperationName(0) + "' " +
737 ErrorMsg);
738 return Op.getOperand(0);
739}
740
741SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
742 SelectionDAG &DAG) const {
743 SDLoc DL(Op);
744 MVT GRLenVT = Subtarget.getGRLenVT();
745 SDValue Op0 = Op.getOperand(0);
746 uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
747 SDValue Op2 = Op.getOperand(2);
748 const StringRef ErrorMsgOOR = "out of range";
749
750 switch (IntrinsicEnum) {
751 default:
752 // TODO: Add more Intrinsics.
753 return SDValue();
754 case Intrinsic::loongarch_cacop_d:
755 case Intrinsic::loongarch_cacop_w: {
756 if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) {
757 DAG.getContext()->emitError(
758 "llvm.loongarch.cacop.d requires target: loongarch64");
759 return Op.getOperand(0);
760 }
761 if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) {
762 DAG.getContext()->emitError(
763 "llvm.loongarch.cacop.w requires target: loongarch32");
764 return Op.getOperand(0);
765 }
766 // call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
767 unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
768 if (!isUInt<5>(Imm1))
769 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
770 SDValue Op4 = Op.getOperand(4);
771 int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue();
772 if (!isInt<12>(Imm2))
773 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
774
775 return Op;
776 }
777
778 case Intrinsic::loongarch_dbar: {
779 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
780 if (!isUInt<15>(Imm))
781 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
782
783 return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0,
784 DAG.getConstant(Imm, DL, GRLenVT));
785 }
786 case Intrinsic::loongarch_ibar: {
787 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
788 if (!isUInt<15>(Imm))
789 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
790
791 return DAG.getNode(LoongArchISD::IBAR, DL, MVT::Other, Op0,
792 DAG.getConstant(Imm, DL, GRLenVT));
793 }
794 case Intrinsic::loongarch_break: {
795 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
796 if (!isUInt<15>(Imm))
797 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
798
799 return DAG.getNode(LoongArchISD::BREAK, DL, MVT::Other, Op0,
800 DAG.getConstant(Imm, DL, GRLenVT));
801 }
802 case Intrinsic::loongarch_movgr2fcsr: {
803 if (!Subtarget.hasBasicF()) {
804 DAG.getContext()->emitError(
805 "llvm.loongarch.movgr2fcsr expects basic f target feature");
806 return Op0;
807 }
808 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
809 if (!isUInt<2>(Imm))
810 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
811
812 return DAG.getNode(
814 DAG.getConstant(Imm, DL, GRLenVT),
815 DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Op.getOperand(3)));
816 }
817 case Intrinsic::loongarch_syscall: {
818 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
819 if (!isUInt<15>(Imm))
820 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
821
822 return DAG.getNode(LoongArchISD::SYSCALL, DL, MVT::Other, Op0,
823 DAG.getConstant(Imm, DL, GRLenVT));
824 }
825#define IOCSRWR_CASE(NAME, NODE) \
826 case Intrinsic::loongarch_##NAME: { \
827 SDValue Op3 = Op.getOperand(3); \
828 if (Subtarget.is64Bit()) \
829 return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, \
830 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
831 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op3)); \
832 else \
833 return DAG.getNode(LoongArchISD::NODE, DL, MVT::Other, Op0, Op2, Op3); \
834 }
835 IOCSRWR_CASE(iocsrwr_b, IOCSRWR_B);
836 IOCSRWR_CASE(iocsrwr_h, IOCSRWR_H);
837 IOCSRWR_CASE(iocsrwr_w, IOCSRWR_W);
838#undef IOCSRWR_CASE
839 case Intrinsic::loongarch_iocsrwr_d: {
840 if (Subtarget.is64Bit())
841 return DAG.getNode(
843 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op.getOperand(3)));
844 else {
845 DAG.getContext()->emitError(
846 "llvm.loongarch.iocsrwr.d requires target: loongarch64");
847 return Op.getOperand(0);
848 }
849 }
850#define ASRT_LE_GT_CASE(NAME) \
851 case Intrinsic::loongarch_##NAME: { \
852 if (!Subtarget.is64Bit()) { \
853 DAG.getContext()->emitError(Op->getOperationName(0) + \
854 " requires target: loongarch64"); \
855 return Op.getOperand(0); \
856 } \
857 return Op; \
858 }
859 ASRT_LE_GT_CASE(asrtle_d)
860 ASRT_LE_GT_CASE(asrtgt_d)
861#undef ASRT_LE_GT_CASE
862 case Intrinsic::loongarch_ldpte_d: {
863 unsigned Imm = cast<ConstantSDNode>(Op.getOperand(3))->getZExtValue();
864 if (!isUInt<8>(Imm))
865 return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
866 if (!Subtarget.is64Bit()) {
867 DAG.getContext()->emitError(Op->getOperationName(0) +
868 " requires target: loongarch64");
869 return Op.getOperand(0);
870 }
871 return Op;
872 }
873 }
874}
875
876SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op,
877 SelectionDAG &DAG) const {
878 SDLoc DL(Op);
879 SDValue Lo = Op.getOperand(0);
880 SDValue Hi = Op.getOperand(1);
881 SDValue Shamt = Op.getOperand(2);
882 EVT VT = Lo.getValueType();
883
884 // if Shamt-GRLen < 0: // Shamt < GRLen
885 // Lo = Lo << Shamt
886 // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
887 // else:
888 // Lo = 0
889 // Hi = Lo << (Shamt-GRLen)
890
891 SDValue Zero = DAG.getConstant(0, DL, VT);
892 SDValue One = DAG.getConstant(1, DL, VT);
893 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
894 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
895 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
896 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
897
898 SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt);
899 SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One);
900 SDValue ShiftRightLo =
901 DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
902 SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt);
903 SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
904 SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
905
906 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
907
908 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero);
909 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
910
911 SDValue Parts[2] = {Lo, Hi};
912 return DAG.getMergeValues(Parts, DL);
913}
914
915SDValue LoongArchTargetLowering::lowerShiftRightParts(SDValue Op,
916 SelectionDAG &DAG,
917 bool IsSRA) const {
918 SDLoc DL(Op);
919 SDValue Lo = Op.getOperand(0);
920 SDValue Hi = Op.getOperand(1);
921 SDValue Shamt = Op.getOperand(2);
922 EVT VT = Lo.getValueType();
923
924 // SRA expansion:
925 // if Shamt-GRLen < 0: // Shamt < GRLen
926 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
927 // Hi = Hi >>s Shamt
928 // else:
929 // Lo = Hi >>s (Shamt-GRLen);
930 // Hi = Hi >>s (GRLen-1)
931 //
932 // SRL expansion:
933 // if Shamt-GRLen < 0: // Shamt < GRLen
934 // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
935 // Hi = Hi >>u Shamt
936 // else:
937 // Lo = Hi >>u (Shamt-GRLen);
938 // Hi = 0;
939
940 unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
941
942 SDValue Zero = DAG.getConstant(0, DL, VT);
943 SDValue One = DAG.getConstant(1, DL, VT);
944 SDValue MinusGRLen = DAG.getConstant(-(int)Subtarget.getGRLen(), DL, VT);
945 SDValue GRLenMinus1 = DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT);
946 SDValue ShamtMinusGRLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusGRLen);
947 SDValue GRLenMinus1Shamt = DAG.getNode(ISD::XOR, DL, VT, Shamt, GRLenMinus1);
948
949 SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt);
950 SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One);
951 SDValue ShiftLeftHi =
952 DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
953 SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
954 SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt);
955 SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
956 SDValue HiFalse =
957 IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
958
959 SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
960
961 Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
962 Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
963
964 SDValue Parts[2] = {Lo, Hi};
965 return DAG.getMergeValues(Parts, DL);
966}
967
968// Returns the opcode of the target-specific SDNode that implements the 32-bit
969// form of the given Opcode.
971 switch (Opcode) {
972 default:
973 llvm_unreachable("Unexpected opcode");
974 case ISD::SHL:
975 return LoongArchISD::SLL_W;
976 case ISD::SRA:
977 return LoongArchISD::SRA_W;
978 case ISD::SRL:
979 return LoongArchISD::SRL_W;
980 case ISD::ROTR:
982 case ISD::ROTL:
984 case ISD::CTTZ:
985 return LoongArchISD::CTZ_W;
986 case ISD::CTLZ:
987 return LoongArchISD::CLZ_W;
988 }
989}
990
991// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
992// node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
993// otherwise be promoted to i64, making it difficult to select the
994// SLL_W/.../*W later one because the fact the operation was originally of
995// type i8/i16/i32 is lost.
997 unsigned ExtOpc = ISD::ANY_EXTEND) {
998 SDLoc DL(N);
999 LoongArchISD::NodeType WOpcode = getLoongArchWOpcode(N->getOpcode());
1000 SDValue NewOp0, NewRes;
1001
1002 switch (NumOp) {
1003 default:
1004 llvm_unreachable("Unexpected NumOp");
1005 case 1: {
1006 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1007 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0);
1008 break;
1009 }
1010 case 2: {
1011 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1012 SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
1013 NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
1014 break;
1015 }
1016 // TODO:Handle more NumOp.
1017 }
1018
1019 // ReplaceNodeResults requires we maintain the same type for the return
1020 // value.
1021 return DAG.getNode(ISD::TRUNCATE, DL, N->getValueType(0), NewRes);
1022}
1023
1026 SDLoc DL(N);
1027 EVT VT = N->getValueType(0);
1028 switch (N->getOpcode()) {
1029 default:
1030 llvm_unreachable("Don't know how to legalize this operation");
1031 case ISD::SHL:
1032 case ISD::SRA:
1033 case ISD::SRL:
1034 case ISD::ROTR:
1035 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1036 "Unexpected custom legalisation");
1037 if (N->getOperand(1).getOpcode() != ISD::Constant) {
1038 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1039 break;
1040 }
1041 break;
1042 case ISD::ROTL:
1043 ConstantSDNode *CN;
1044 if ((CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))) {
1045 Results.push_back(customLegalizeToWOp(N, DAG, 2));
1046 break;
1047 }
1048 break;
1049 case ISD::FP_TO_SINT: {
1050 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1051 "Unexpected custom legalisation");
1052 SDValue Src = N->getOperand(0);
1053 EVT FVT = EVT::getFloatingPointVT(N->getValueSizeInBits(0));
1054 if (getTypeAction(*DAG.getContext(), Src.getValueType()) !=
1056 SDValue Dst = DAG.getNode(LoongArchISD::FTINT, DL, FVT, Src);
1057 Results.push_back(DAG.getNode(ISD::BITCAST, DL, VT, Dst));
1058 return;
1059 }
1060 // If the FP type needs to be softened, emit a library call using the 'si'
1061 // version. If we left it to default legalization we'd end up with 'di'.
1062 RTLIB::Libcall LC;
1063 LC = RTLIB::getFPTOSINT(Src.getValueType(), VT);
1064 MakeLibCallOptions CallOptions;
1065 EVT OpVT = Src.getValueType();
1066 CallOptions.setTypeListBeforeSoften(OpVT, VT, true);
1067 SDValue Chain = SDValue();
1068 SDValue Result;
1069 std::tie(Result, Chain) =
1070 makeLibCall(DAG, LC, VT, Src, CallOptions, DL, Chain);
1071 Results.push_back(Result);
1072 break;
1073 }
1074 case ISD::BITCAST: {
1075 SDValue Src = N->getOperand(0);
1076 EVT SrcVT = Src.getValueType();
1077 if (VT == MVT::i32 && SrcVT == MVT::f32 && Subtarget.is64Bit() &&
1078 Subtarget.hasBasicF()) {
1079 SDValue Dst =
1081 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Dst));
1082 }
1083 break;
1084 }
1085 case ISD::FP_TO_UINT: {
1086 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1087 "Unexpected custom legalisation");
1088 auto &TLI = DAG.getTargetLoweringInfo();
1089 SDValue Tmp1, Tmp2;
1090 TLI.expandFP_TO_UINT(N, Tmp1, Tmp2, DAG);
1091 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, Tmp1));
1092 break;
1093 }
1094 case ISD::BSWAP: {
1095 SDValue Src = N->getOperand(0);
1096 assert((VT == MVT::i16 || VT == MVT::i32) &&
1097 "Unexpected custom legalization");
1098 MVT GRLenVT = Subtarget.getGRLenVT();
1099 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1100 SDValue Tmp;
1101 switch (VT.getSizeInBits()) {
1102 default:
1103 llvm_unreachable("Unexpected operand width");
1104 case 16:
1105 Tmp = DAG.getNode(LoongArchISD::REVB_2H, DL, GRLenVT, NewSrc);
1106 break;
1107 case 32:
1108 // Only LA64 will get to here due to the size mismatch between VT and
1109 // GRLenVT, LA32 lowering is directly defined in LoongArchInstrInfo.
1110 Tmp = DAG.getNode(LoongArchISD::REVB_2W, DL, GRLenVT, NewSrc);
1111 break;
1112 }
1113 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1114 break;
1115 }
1116 case ISD::BITREVERSE: {
1117 SDValue Src = N->getOperand(0);
1118 assert((VT == MVT::i8 || (VT == MVT::i32 && Subtarget.is64Bit())) &&
1119 "Unexpected custom legalization");
1120 MVT GRLenVT = Subtarget.getGRLenVT();
1121 SDValue NewSrc = DAG.getNode(ISD::ANY_EXTEND, DL, GRLenVT, Src);
1122 SDValue Tmp;
1123 switch (VT.getSizeInBits()) {
1124 default:
1125 llvm_unreachable("Unexpected operand width");
1126 case 8:
1127 Tmp = DAG.getNode(LoongArchISD::BITREV_4B, DL, GRLenVT, NewSrc);
1128 break;
1129 case 32:
1130 Tmp = DAG.getNode(LoongArchISD::BITREV_W, DL, GRLenVT, NewSrc);
1131 break;
1132 }
1133 Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, VT, Tmp));
1134 break;
1135 }
1136 case ISD::CTLZ:
1137 case ISD::CTTZ: {
1138 assert(VT == MVT::i32 && Subtarget.is64Bit() &&
1139 "Unexpected custom legalisation");
1140 Results.push_back(customLegalizeToWOp(N, DAG, 1));
1141 break;
1142 }
1144 SDValue Op0 = N->getOperand(0);
1145 EVT VT = N->getValueType(0);
1146 uint64_t Op1 = N->getConstantOperandVal(1);
1147 MVT GRLenVT = Subtarget.getGRLenVT();
1148 if (Op1 == Intrinsic::loongarch_movfcsr2gr) {
1149 if (!Subtarget.hasBasicF()) {
1150 DAG.getContext()->emitError(
1151 "llvm.loongarch.movfcsr2gr expects basic f target feature");
1152 Results.push_back(DAG.getMergeValues(
1153 {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1154 Results.push_back(N->getOperand(0));
1155 return;
1156 }
1157 unsigned Imm = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue();
1158 if (!isUInt<2>(Imm)) {
1159 DAG.getContext()->emitError("argument to '" + N->getOperationName(0) +
1160 "' " + "out of range");
1161 Results.push_back(DAG.getMergeValues(
1162 {DAG.getUNDEF(N->getValueType(0)), N->getOperand(0)}, SDLoc(N)));
1163 Results.push_back(N->getOperand(0));
1164 return;
1165 }
1166 Results.push_back(
1167 DAG.getNode(ISD::TRUNCATE, DL, VT,
1169 DAG.getConstant(Imm, DL, GRLenVT))));
1170 Results.push_back(N->getOperand(0));
1171 return;
1172 }
1173 SDValue Op2 = N->getOperand(2);
1174 std::string Name = N->getOperationName(0);
1175
1176 switch (Op1) {
1177 default:
1178 llvm_unreachable("Unexpected Intrinsic.");
1179#define CRC_CASE_EXT_BINARYOP(NAME, NODE) \
1180 case Intrinsic::loongarch_##NAME: { \
1181 Results.push_back(DAG.getNode( \
1182 ISD::TRUNCATE, DL, VT, \
1183 DAG.getNode( \
1184 LoongArchISD::NODE, DL, MVT::i64, \
1185 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2), \
1186 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3))))); \
1187 Results.push_back(N->getOperand(0)); \
1188 break; \
1189 }
1190 CRC_CASE_EXT_BINARYOP(crc_w_b_w, CRC_W_B_W)
1191 CRC_CASE_EXT_BINARYOP(crc_w_h_w, CRC_W_H_W)
1192 CRC_CASE_EXT_BINARYOP(crc_w_w_w, CRC_W_W_W)
1193 CRC_CASE_EXT_BINARYOP(crcc_w_b_w, CRCC_W_B_W)
1194 CRC_CASE_EXT_BINARYOP(crcc_w_h_w, CRCC_W_H_W)
1195 CRC_CASE_EXT_BINARYOP(crcc_w_w_w, CRCC_W_W_W)
1196#undef CRC_CASE_EXT_BINARYOP
1197
1198#define CRC_CASE_EXT_UNARYOP(NAME, NODE) \
1199 case Intrinsic::loongarch_##NAME: { \
1200 Results.push_back( \
1201 DAG.getNode(ISD::TRUNCATE, DL, VT, \
1202 DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op2, \
1203 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, \
1204 N->getOperand(3))))); \
1205 Results.push_back(N->getOperand(0)); \
1206 break; \
1207 }
1208 CRC_CASE_EXT_UNARYOP(crc_w_d_w, CRC_W_D_W)
1209 CRC_CASE_EXT_UNARYOP(crcc_w_d_w, CRCC_W_D_W)
1210#undef CRC_CASE_EXT_UNARYOP
1211#define CSR_CASE(ID) \
1212 case Intrinsic::loongarch_##ID: { \
1213 if (!Subtarget.is64Bit()) { \
1214 DAG.getContext()->emitError(Name + " requires target: loongarch64"); \
1215 Results.push_back(DAG.getUNDEF(VT)); \
1216 Results.push_back(N->getOperand(0)); \
1217 } \
1218 break; \
1219 }
1220 CSR_CASE(csrrd_d);
1221 CSR_CASE(csrwr_d);
1222 CSR_CASE(csrxchg_d);
1223 CSR_CASE(iocsrrd_d);
1224#undef CSR_CASE
1225 case Intrinsic::loongarch_csrrd_w: {
1226 unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
1227 if (!isUInt<14>(Imm)) {
1228 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1229 Results.push_back(DAG.getUNDEF(VT));
1230 Results.push_back(N->getOperand(0));
1231 break;
1232 }
1233
1234 Results.push_back(
1235 DAG.getNode(ISD::TRUNCATE, DL, VT,
1236 DAG.getNode(LoongArchISD::CSRRD, DL, GRLenVT, Op0,
1237 DAG.getConstant(Imm, DL, GRLenVT))));
1238 Results.push_back(N->getOperand(0));
1239 break;
1240 }
1241 case Intrinsic::loongarch_csrwr_w: {
1242 unsigned Imm = cast<ConstantSDNode>(N->getOperand(3))->getZExtValue();
1243 if (!isUInt<14>(Imm)) {
1244 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1245 Results.push_back(DAG.getUNDEF(VT));
1246 Results.push_back(N->getOperand(0));
1247 break;
1248 }
1249
1250 Results.push_back(DAG.getNode(
1251 ISD::TRUNCATE, DL, VT,
1252 DAG.getNode(LoongArchISD::CSRWR, DL, GRLenVT, Op0,
1253 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1254 DAG.getConstant(Imm, DL, GRLenVT))));
1255 Results.push_back(N->getOperand(0));
1256 break;
1257 }
1258 case Intrinsic::loongarch_csrxchg_w: {
1259 unsigned Imm = cast<ConstantSDNode>(N->getOperand(4))->getZExtValue();
1260 if (!isUInt<14>(Imm)) {
1261 DAG.getContext()->emitError("argument to '" + Name + "' out of range");
1262 Results.push_back(DAG.getUNDEF(VT));
1263 Results.push_back(N->getOperand(0));
1264 break;
1265 }
1266
1267 Results.push_back(DAG.getNode(
1268 ISD::TRUNCATE, DL, VT,
1269 DAG.getNode(
1270 LoongArchISD::CSRXCHG, DL, GRLenVT, Op0,
1271 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2),
1272 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(3)),
1273 DAG.getConstant(Imm, DL, GRLenVT))));
1274 Results.push_back(N->getOperand(0));
1275 break;
1276 }
1277#define IOCSRRD_CASE(NAME, NODE) \
1278 case Intrinsic::loongarch_##NAME: { \
1279 Results.push_back(DAG.getNode( \
1280 ISD::TRUNCATE, DL, N->getValueType(0), \
1281 DAG.getNode(LoongArchISD::NODE, DL, MVT::i64, Op0, \
1282 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2)))); \
1283 Results.push_back(N->getOperand(0)); \
1284 break; \
1285 }
1286 IOCSRRD_CASE(iocsrrd_b, IOCSRRD_B);
1287 IOCSRRD_CASE(iocsrrd_h, IOCSRRD_H);
1288 IOCSRRD_CASE(iocsrrd_w, IOCSRRD_W);
1289#undef IOCSRRD_CASE
1290 case Intrinsic::loongarch_cpucfg: {
1291 Results.push_back(DAG.getNode(
1292 ISD::TRUNCATE, DL, VT,
1293 DAG.getNode(LoongArchISD::CPUCFG, DL, GRLenVT, Op0,
1294 DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op2))));
1295 Results.push_back(Op0);
1296 break;
1297 }
1298 case Intrinsic::loongarch_lddir_d: {
1299 if (!Subtarget.is64Bit()) {
1300 DAG.getContext()->emitError(N->getOperationName(0) +
1301 " requires target: loongarch64");
1302 Results.push_back(DAG.getUNDEF(VT));
1303 Results.push_back(Op0);
1304 break;
1305 }
1306 break;
1307 }
1308 }
1309 break;
1310 }
1311 case ISD::READ_REGISTER: {
1312 if (Subtarget.is64Bit())
1313 DAG.getContext()->emitError(
1314 "On LA64, only 64-bit registers can be read.");
1315 else
1316 DAG.getContext()->emitError(
1317 "On LA32, only 32-bit registers can be read.");
1318 Results.push_back(DAG.getUNDEF(VT));
1319 Results.push_back(N->getOperand(0));
1320 break;
1321 }
1322 }
1323}
1324
1327 const LoongArchSubtarget &Subtarget) {
1328 if (DCI.isBeforeLegalizeOps())
1329 return SDValue();
1330
1331 SDValue FirstOperand = N->getOperand(0);
1332 SDValue SecondOperand = N->getOperand(1);
1333 unsigned FirstOperandOpc = FirstOperand.getOpcode();
1334 EVT ValTy = N->getValueType(0);
1335 SDLoc DL(N);
1336 uint64_t lsb, msb;
1337 unsigned SMIdx, SMLen;
1338 ConstantSDNode *CN;
1339 SDValue NewOperand;
1340 MVT GRLenVT = Subtarget.getGRLenVT();
1341
1342 // Op's second operand must be a shifted mask.
1343 if (!(CN = dyn_cast<ConstantSDNode>(SecondOperand)) ||
1344 !isShiftedMask_64(CN->getZExtValue(), SMIdx, SMLen))
1345 return SDValue();
1346
1347 if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL) {
1348 // Pattern match BSTRPICK.
1349 // $dst = and ((sra or srl) $src , lsb), (2**len - 1)
1350 // => BSTRPICK $dst, $src, msb, lsb
1351 // where msb = lsb + len - 1
1352
1353 // The second operand of the shift must be an immediate.
1354 if (!(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))))
1355 return SDValue();
1356
1357 lsb = CN->getZExtValue();
1358
1359 // Return if the shifted mask does not start at bit 0 or the sum of its
1360 // length and lsb exceeds the word's size.
1361 if (SMIdx != 0 || lsb + SMLen > ValTy.getSizeInBits())
1362 return SDValue();
1363
1364 NewOperand = FirstOperand.getOperand(0);
1365 } else {
1366 // Pattern match BSTRPICK.
1367 // $dst = and $src, (2**len- 1) , if len > 12
1368 // => BSTRPICK $dst, $src, msb, lsb
1369 // where lsb = 0 and msb = len - 1
1370
1371 // If the mask is <= 0xfff, andi can be used instead.
1372 if (CN->getZExtValue() <= 0xfff)
1373 return SDValue();
1374
1375 // Return if the mask doesn't start at position 0.
1376 if (SMIdx)
1377 return SDValue();
1378
1379 lsb = 0;
1380 NewOperand = FirstOperand;
1381 }
1382 msb = lsb + SMLen - 1;
1383 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
1384 DAG.getConstant(msb, DL, GRLenVT),
1385 DAG.getConstant(lsb, DL, GRLenVT));
1386}
1387
1390 const LoongArchSubtarget &Subtarget) {
1391 if (DCI.isBeforeLegalizeOps())
1392 return SDValue();
1393
1394 // $dst = srl (and $src, Mask), Shamt
1395 // =>
1396 // BSTRPICK $dst, $src, MaskIdx+MaskLen-1, Shamt
1397 // when Mask is a shifted mask, and MaskIdx <= Shamt <= MaskIdx+MaskLen-1
1398 //
1399
1400 SDValue FirstOperand = N->getOperand(0);
1401 ConstantSDNode *CN;
1402 EVT ValTy = N->getValueType(0);
1403 SDLoc DL(N);
1404 MVT GRLenVT = Subtarget.getGRLenVT();
1405 unsigned MaskIdx, MaskLen;
1406 uint64_t Shamt;
1407
1408 // The first operand must be an AND and the second operand of the AND must be
1409 // a shifted mask.
1410 if (FirstOperand.getOpcode() != ISD::AND ||
1411 !(CN = dyn_cast<ConstantSDNode>(FirstOperand.getOperand(1))) ||
1412 !isShiftedMask_64(CN->getZExtValue(), MaskIdx, MaskLen))
1413 return SDValue();
1414
1415 // The second operand (shift amount) must be an immediate.
1416 if (!(CN = dyn_cast<ConstantSDNode>(N->getOperand(1))))
1417 return SDValue();
1418
1419 Shamt = CN->getZExtValue();
1420 if (MaskIdx <= Shamt && Shamt <= MaskIdx + MaskLen - 1)
1421 return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy,
1422 FirstOperand->getOperand(0),
1423 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1424 DAG.getConstant(Shamt, DL, GRLenVT));
1425
1426 return SDValue();
1427}
1428
1431 const LoongArchSubtarget &Subtarget) {
1432 MVT GRLenVT = Subtarget.getGRLenVT();
1433 EVT ValTy = N->getValueType(0);
1434 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
1435 ConstantSDNode *CN0, *CN1;
1436 SDLoc DL(N);
1437 unsigned ValBits = ValTy.getSizeInBits();
1438 unsigned MaskIdx0, MaskLen0, MaskIdx1, MaskLen1;
1439 unsigned Shamt;
1440 bool SwapAndRetried = false;
1441
1442 if (DCI.isBeforeLegalizeOps())
1443 return SDValue();
1444
1445 if (ValBits != 32 && ValBits != 64)
1446 return SDValue();
1447
1448Retry:
1449 // 1st pattern to match BSTRINS:
1450 // R = or (and X, mask0), (and (shl Y, lsb), mask1)
1451 // where mask1 = (2**size - 1) << lsb, mask0 = ~mask1
1452 // =>
1453 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1454 if (N0.getOpcode() == ISD::AND &&
1455 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1456 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1457 N1.getOpcode() == ISD::AND && N1.getOperand(0).getOpcode() == ISD::SHL &&
1458 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1459 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1460 MaskIdx0 == MaskIdx1 && MaskLen0 == MaskLen1 &&
1461 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1462 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1463 (MaskIdx0 + MaskLen0 <= ValBits)) {
1464 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 1\n");
1465 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1466 N1.getOperand(0).getOperand(0),
1467 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1468 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1469 }
1470
1471 // 2nd pattern to match BSTRINS:
1472 // R = or (and X, mask0), (shl (and Y, mask1), lsb)
1473 // where mask1 = (2**size - 1), mask0 = ~(mask1 << lsb)
1474 // =>
1475 // R = BSTRINS X, Y, msb, lsb (where msb = lsb + size - 1)
1476 if (N0.getOpcode() == ISD::AND &&
1477 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1478 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1479 N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1480 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1481 (Shamt = CN1->getZExtValue()) == MaskIdx0 &&
1482 (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1483 isShiftedMask_64(CN1->getZExtValue(), MaskIdx1, MaskLen1) &&
1484 MaskLen0 == MaskLen1 && MaskIdx1 == 0 &&
1485 (MaskIdx0 + MaskLen0 <= ValBits)) {
1486 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 2\n");
1487 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1488 N1.getOperand(0).getOperand(0),
1489 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1490 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1491 }
1492
1493 // 3rd pattern to match BSTRINS:
1494 // R = or (and X, mask0), (and Y, mask1)
1495 // where ~mask0 = (2**size - 1) << lsb, mask0 & mask1 = 0
1496 // =>
1497 // R = BSTRINS X, (shr (and Y, mask1), lsb), msb, lsb
1498 // where msb = lsb + size - 1
1499 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::AND &&
1500 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1501 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1502 (MaskIdx0 + MaskLen0 <= 64) &&
1503 (CN1 = dyn_cast<ConstantSDNode>(N1->getOperand(1))) &&
1504 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1505 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 3\n");
1506 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1507 DAG.getNode(ISD::SRL, DL, N1->getValueType(0), N1,
1508 DAG.getConstant(MaskIdx0, DL, GRLenVT)),
1509 DAG.getConstant(ValBits == 32
1510 ? (MaskIdx0 + (MaskLen0 & 31) - 1)
1511 : (MaskIdx0 + MaskLen0 - 1),
1512 DL, GRLenVT),
1513 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1514 }
1515
1516 // 4th pattern to match BSTRINS:
1517 // R = or (and X, mask), (shl Y, shamt)
1518 // where mask = (2**shamt - 1)
1519 // =>
1520 // R = BSTRINS X, Y, ValBits - 1, shamt
1521 // where ValBits = 32 or 64
1522 if (N0.getOpcode() == ISD::AND && N1.getOpcode() == ISD::SHL &&
1523 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1524 isShiftedMask_64(CN0->getZExtValue(), MaskIdx0, MaskLen0) &&
1525 MaskIdx0 == 0 && (CN1 = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1526 (Shamt = CN1->getZExtValue()) == MaskLen0 &&
1527 (MaskIdx0 + MaskLen0 <= ValBits)) {
1528 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 4\n");
1529 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1530 N1.getOperand(0),
1531 DAG.getConstant((ValBits - 1), DL, GRLenVT),
1532 DAG.getConstant(Shamt, DL, GRLenVT));
1533 }
1534
1535 // 5th pattern to match BSTRINS:
1536 // R = or (and X, mask), const
1537 // where ~mask = (2**size - 1) << lsb, mask & const = 0
1538 // =>
1539 // R = BSTRINS X, (const >> lsb), msb, lsb
1540 // where msb = lsb + size - 1
1541 if (N0.getOpcode() == ISD::AND &&
1542 (CN0 = dyn_cast<ConstantSDNode>(N0.getOperand(1))) &&
1543 isShiftedMask_64(~CN0->getSExtValue(), MaskIdx0, MaskLen0) &&
1544 (CN1 = dyn_cast<ConstantSDNode>(N1)) &&
1545 (CN1->getSExtValue() & CN0->getSExtValue()) == 0) {
1546 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 5\n");
1547 return DAG.getNode(
1548 LoongArchISD::BSTRINS, DL, ValTy, N0.getOperand(0),
1549 DAG.getConstant(CN1->getSExtValue() >> MaskIdx0, DL, ValTy),
1550 DAG.getConstant((MaskIdx0 + MaskLen0 - 1), DL, GRLenVT),
1551 DAG.getConstant(MaskIdx0, DL, GRLenVT));
1552 }
1553
1554 // 6th pattern.
1555 // a = b | ((c & mask) << shamt), where all positions in b to be overwritten
1556 // by the incoming bits are known to be zero.
1557 // =>
1558 // a = BSTRINS b, c, shamt + MaskLen - 1, shamt
1559 //
1560 // Note that the 1st pattern is a special situation of the 6th, i.e. the 6th
1561 // pattern is more common than the 1st. So we put the 1st before the 6th in
1562 // order to match as many nodes as possible.
1563 ConstantSDNode *CNMask, *CNShamt;
1564 unsigned MaskIdx, MaskLen;
1565 if (N1.getOpcode() == ISD::SHL && N1.getOperand(0).getOpcode() == ISD::AND &&
1566 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1567 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1568 MaskIdx == 0 && (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1569 CNShamt->getZExtValue() + MaskLen <= ValBits) {
1570 Shamt = CNShamt->getZExtValue();
1571 APInt ShMask(ValBits, CNMask->getZExtValue() << Shamt);
1572 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1573 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 6\n");
1574 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1575 N1.getOperand(0).getOperand(0),
1576 DAG.getConstant(Shamt + MaskLen - 1, DL, GRLenVT),
1577 DAG.getConstant(Shamt, DL, GRLenVT));
1578 }
1579 }
1580
1581 // 7th pattern.
1582 // a = b | ((c << shamt) & shifted_mask), where all positions in b to be
1583 // overwritten by the incoming bits are known to be zero.
1584 // =>
1585 // a = BSTRINS b, c, MaskIdx + MaskLen - 1, MaskIdx
1586 //
1587 // Similarly, the 7th pattern is more common than the 2nd. So we put the 2nd
1588 // before the 7th in order to match as many nodes as possible.
1589 if (N1.getOpcode() == ISD::AND &&
1590 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1591 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen) &&
1592 N1.getOperand(0).getOpcode() == ISD::SHL &&
1593 (CNShamt = dyn_cast<ConstantSDNode>(N1.getOperand(0).getOperand(1))) &&
1594 CNShamt->getZExtValue() == MaskIdx) {
1595 APInt ShMask(ValBits, CNMask->getZExtValue());
1596 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1597 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 7\n");
1598 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1599 N1.getOperand(0).getOperand(0),
1600 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1601 DAG.getConstant(MaskIdx, DL, GRLenVT));
1602 }
1603 }
1604
1605 // (or a, b) and (or b, a) are equivalent, so swap the operands and retry.
1606 if (!SwapAndRetried) {
1607 std::swap(N0, N1);
1608 SwapAndRetried = true;
1609 goto Retry;
1610 }
1611
1612 SwapAndRetried = false;
1613Retry2:
1614 // 8th pattern.
1615 // a = b | (c & shifted_mask), where all positions in b to be overwritten by
1616 // the incoming bits are known to be zero.
1617 // =>
1618 // a = BSTRINS b, c >> MaskIdx, MaskIdx + MaskLen - 1, MaskIdx
1619 //
1620 // Similarly, the 8th pattern is more common than the 4th and 5th patterns. So
1621 // we put it here in order to match as many nodes as possible or generate less
1622 // instructions.
1623 if (N1.getOpcode() == ISD::AND &&
1624 (CNMask = dyn_cast<ConstantSDNode>(N1.getOperand(1))) &&
1625 isShiftedMask_64(CNMask->getZExtValue(), MaskIdx, MaskLen)) {
1626 APInt ShMask(ValBits, CNMask->getZExtValue());
1627 if (ShMask.isSubsetOf(DAG.computeKnownBits(N0).Zero)) {
1628 LLVM_DEBUG(dbgs() << "Perform OR combine: match pattern 8\n");
1629 return DAG.getNode(LoongArchISD::BSTRINS, DL, ValTy, N0,
1630 DAG.getNode(ISD::SRL, DL, N1->getValueType(0),
1631 N1->getOperand(0),
1632 DAG.getConstant(MaskIdx, DL, GRLenVT)),
1633 DAG.getConstant(MaskIdx + MaskLen - 1, DL, GRLenVT),
1634 DAG.getConstant(MaskIdx, DL, GRLenVT));
1635 }
1636 }
1637 // Swap N0/N1 and retry.
1638 if (!SwapAndRetried) {
1639 std::swap(N0, N1);
1640 SwapAndRetried = true;
1641 goto Retry2;
1642 }
1643
1644 return SDValue();
1645}
1646
1647// Combine (loongarch_bitrev_w (loongarch_revb_2w X)) to loongarch_bitrev_4b.
1650 const LoongArchSubtarget &Subtarget) {
1651 if (DCI.isBeforeLegalizeOps())
1652 return SDValue();
1653
1654 SDValue Src = N->getOperand(0);
1655 if (Src.getOpcode() != LoongArchISD::REVB_2W)
1656 return SDValue();
1657
1658 return DAG.getNode(LoongArchISD::BITREV_4B, SDLoc(N), N->getValueType(0),
1659 Src.getOperand(0));
1660}
1661
1663 DAGCombinerInfo &DCI) const {
1664 SelectionDAG &DAG = DCI.DAG;
1665 switch (N->getOpcode()) {
1666 default:
1667 break;
1668 case ISD::AND:
1669 return performANDCombine(N, DAG, DCI, Subtarget);
1670 case ISD::OR:
1671 return performORCombine(N, DAG, DCI, Subtarget);
1672 case ISD::SRL:
1673 return performSRLCombine(N, DAG, DCI, Subtarget);
1675 return performBITREV_WCombine(N, DAG, DCI, Subtarget);
1676 }
1677 return SDValue();
1678}
1679
1682 if (!ZeroDivCheck)
1683 return MBB;
1684
1685 // Build instructions:
1686 // MBB:
1687 // div(or mod) $dst, $dividend, $divisor
1688 // bnez $divisor, SinkMBB
1689 // BreakMBB:
1690 // break 7 // BRK_DIVZERO
1691 // SinkMBB:
1692 // fallthrough
1693 const BasicBlock *LLVM_BB = MBB->getBasicBlock();
1695 MachineFunction *MF = MBB->getParent();
1696 auto BreakMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1697 auto SinkMBB = MF->CreateMachineBasicBlock(LLVM_BB);
1698 MF->insert(It, BreakMBB);
1699 MF->insert(It, SinkMBB);
1700
1701 // Transfer the remainder of MBB and its successor edges to SinkMBB.
1702 SinkMBB->splice(SinkMBB->end(), MBB, std::next(MI.getIterator()), MBB->end());
1703 SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
1704
1705 const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
1706 DebugLoc DL = MI.getDebugLoc();
1707 MachineOperand &Divisor = MI.getOperand(2);
1708 Register DivisorReg = Divisor.getReg();
1709
1710 // MBB:
1711 BuildMI(MBB, DL, TII.get(LoongArch::BNEZ))
1712 .addReg(DivisorReg, getKillRegState(Divisor.isKill()))
1713 .addMBB(SinkMBB);
1714 MBB->addSuccessor(BreakMBB);
1715 MBB->addSuccessor(SinkMBB);
1716
1717 // BreakMBB:
1718 // See linux header file arch/loongarch/include/uapi/asm/break.h for the
1719 // definition of BRK_DIVZERO.
1720 BuildMI(BreakMBB, DL, TII.get(LoongArch::BREAK)).addImm(7 /*BRK_DIVZERO*/);
1721 BreakMBB->addSuccessor(SinkMBB);
1722
1723 // Clear Divisor's kill flag.
1724 Divisor.setIsKill(false);
1725
1726 return SinkMBB;
1727}
1728
1729MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
1730 MachineInstr &MI, MachineBasicBlock *BB) const {
1731 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
1732 DebugLoc DL = MI.getDebugLoc();
1733
1734 switch (MI.getOpcode()) {
1735 default:
1736 llvm_unreachable("Unexpected instr type to insert");
1737 case LoongArch::DIV_W:
1738 case LoongArch::DIV_WU:
1739 case LoongArch::MOD_W:
1740 case LoongArch::MOD_WU:
1741 case LoongArch::DIV_D:
1742 case LoongArch::DIV_DU:
1743 case LoongArch::MOD_D:
1744 case LoongArch::MOD_DU:
1745 return insertDivByZeroTrap(MI, BB);
1746 break;
1747 case LoongArch::WRFCSR: {
1748 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVGR2FCSR),
1749 LoongArch::FCSR0 + MI.getOperand(0).getImm())
1750 .addReg(MI.getOperand(1).getReg());
1751 MI.eraseFromParent();
1752 return BB;
1753 }
1754 case LoongArch::RDFCSR: {
1755 MachineInstr *ReadFCSR =
1756 BuildMI(*BB, MI, DL, TII->get(LoongArch::MOVFCSR2GR),
1757 MI.getOperand(0).getReg())
1758 .addReg(LoongArch::FCSR0 + MI.getOperand(1).getImm());
1759 ReadFCSR->getOperand(1).setIsUndef();
1760 MI.eraseFromParent();
1761 return BB;
1762 }
1763 }
1764}
1765
1766const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
1767 switch ((LoongArchISD::NodeType)Opcode) {
1769 break;
1770
1771#define NODE_NAME_CASE(node) \
1772 case LoongArchISD::node: \
1773 return "LoongArchISD::" #node;
1774
1775 // TODO: Add more target-dependent nodes later.
1776 NODE_NAME_CASE(CALL)
1777 NODE_NAME_CASE(RET)
1778 NODE_NAME_CASE(TAIL)
1779 NODE_NAME_CASE(SLL_W)
1780 NODE_NAME_CASE(SRA_W)
1781 NODE_NAME_CASE(SRL_W)
1782 NODE_NAME_CASE(BSTRINS)
1783 NODE_NAME_CASE(BSTRPICK)
1784 NODE_NAME_CASE(MOVGR2FR_W_LA64)
1785 NODE_NAME_CASE(MOVFR2GR_S_LA64)
1786 NODE_NAME_CASE(FTINT)
1787 NODE_NAME_CASE(REVB_2H)
1788 NODE_NAME_CASE(REVB_2W)
1789 NODE_NAME_CASE(BITREV_4B)
1790 NODE_NAME_CASE(BITREV_W)
1791 NODE_NAME_CASE(ROTR_W)
1792 NODE_NAME_CASE(ROTL_W)
1793 NODE_NAME_CASE(CLZ_W)
1794 NODE_NAME_CASE(CTZ_W)
1795 NODE_NAME_CASE(DBAR)
1796 NODE_NAME_CASE(IBAR)
1797 NODE_NAME_CASE(BREAK)
1798 NODE_NAME_CASE(SYSCALL)
1799 NODE_NAME_CASE(CRC_W_B_W)
1800 NODE_NAME_CASE(CRC_W_H_W)
1801 NODE_NAME_CASE(CRC_W_W_W)
1802 NODE_NAME_CASE(CRC_W_D_W)
1803 NODE_NAME_CASE(CRCC_W_B_W)
1804 NODE_NAME_CASE(CRCC_W_H_W)
1805 NODE_NAME_CASE(CRCC_W_W_W)
1806 NODE_NAME_CASE(CRCC_W_D_W)
1807 NODE_NAME_CASE(CSRRD)
1808 NODE_NAME_CASE(CSRWR)
1809 NODE_NAME_CASE(CSRXCHG)
1810 NODE_NAME_CASE(IOCSRRD_B)
1811 NODE_NAME_CASE(IOCSRRD_H)
1812 NODE_NAME_CASE(IOCSRRD_W)
1813 NODE_NAME_CASE(IOCSRRD_D)
1814 NODE_NAME_CASE(IOCSRWR_B)
1815 NODE_NAME_CASE(IOCSRWR_H)
1816 NODE_NAME_CASE(IOCSRWR_W)
1817 NODE_NAME_CASE(IOCSRWR_D)
1818 NODE_NAME_CASE(CPUCFG)
1819 NODE_NAME_CASE(MOVGR2FCSR)
1820 NODE_NAME_CASE(MOVFCSR2GR)
1821 NODE_NAME_CASE(CACOP_D)
1822 NODE_NAME_CASE(CACOP_W)
1823 }
1824#undef NODE_NAME_CASE
1825 return nullptr;
1826}
1827
1828//===----------------------------------------------------------------------===//
1829// Calling Convention Implementation
1830//===----------------------------------------------------------------------===//
1831
1832// Eight general-purpose registers a0-a7 used for passing integer arguments,
1833// with a0-a1 reused to return values. Generally, the GPRs are used to pass
1834// fixed-point arguments, and floating-point arguments when no FPR is available
1835// or with soft float ABI.
1836const MCPhysReg ArgGPRs[] = {LoongArch::R4, LoongArch::R5, LoongArch::R6,
1837 LoongArch::R7, LoongArch::R8, LoongArch::R9,
1838 LoongArch::R10, LoongArch::R11};
1839// Eight floating-point registers fa0-fa7 used for passing floating-point
1840// arguments, and fa0-fa1 are also used to return values.
1841const MCPhysReg ArgFPR32s[] = {LoongArch::F0, LoongArch::F1, LoongArch::F2,
1842 LoongArch::F3, LoongArch::F4, LoongArch::F5,
1843 LoongArch::F6, LoongArch::F7};
1844// FPR32 and FPR64 alias each other.
1846 LoongArch::F0_64, LoongArch::F1_64, LoongArch::F2_64, LoongArch::F3_64,
1847 LoongArch::F4_64, LoongArch::F5_64, LoongArch::F6_64, LoongArch::F7_64};
1848
1849// Pass a 2*GRLen argument that has been split into two GRLen values through
1850// registers or the stack as necessary.
1851static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State,
1852 CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1,
1853 unsigned ValNo2, MVT ValVT2, MVT LocVT2,
1854 ISD::ArgFlagsTy ArgFlags2) {
1855 unsigned GRLenInBytes = GRLen / 8;
1856 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1857 // At least one half can be passed via register.
1858 State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg,
1859 VA1.getLocVT(), CCValAssign::Full));
1860 } else {
1861 // Both halves must be passed on the stack, with proper alignment.
1862 Align StackAlign =
1863 std::max(Align(GRLenInBytes), ArgFlags1.getNonZeroOrigAlign());
1864 State.addLoc(
1866 State.AllocateStack(GRLenInBytes, StackAlign),
1867 VA1.getLocVT(), CCValAssign::Full));
1869 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1870 LocVT2, CCValAssign::Full));
1871 return false;
1872 }
1873 if (Register Reg = State.AllocateReg(ArgGPRs)) {
1874 // The second half can also be passed via register.
1875 State.addLoc(
1876 CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full));
1877 } else {
1878 // The second half is passed via the stack, without additional alignment.
1880 ValNo2, ValVT2, State.AllocateStack(GRLenInBytes, Align(GRLenInBytes)),
1881 LocVT2, CCValAssign::Full));
1882 }
1883 return false;
1884}
1885
1886// Implements the LoongArch calling convention. Returns true upon failure.
1888 unsigned ValNo, MVT ValVT,
1889 CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
1890 CCState &State, bool IsFixed, bool IsRet,
1891 Type *OrigTy) {
1892 unsigned GRLen = DL.getLargestLegalIntTypeSizeInBits();
1893 assert((GRLen == 32 || GRLen == 64) && "Unspport GRLen");
1894 MVT GRLenVT = GRLen == 32 ? MVT::i32 : MVT::i64;
1895 MVT LocVT = ValVT;
1896
1897 // Any return value split into more than two values can't be returned
1898 // directly.
1899 if (IsRet && ValNo > 1)
1900 return true;
1901
1902 // If passing a variadic argument, or if no FPR is available.
1903 bool UseGPRForFloat = true;
1904
1905 switch (ABI) {
1906 default:
1907 llvm_unreachable("Unexpected ABI");
1912 report_fatal_error("Unimplemented ABI");
1913 break;
1916 UseGPRForFloat = !IsFixed;
1917 break;
1918 }
1919
1920 // FPR32 and FPR64 alias each other.
1921 if (State.getFirstUnallocated(ArgFPR32s) == std::size(ArgFPR32s))
1922 UseGPRForFloat = true;
1923
1924 if (UseGPRForFloat && ValVT == MVT::f32) {
1925 LocVT = GRLenVT;
1926 LocInfo = CCValAssign::BCvt;
1927 } else if (UseGPRForFloat && GRLen == 64 && ValVT == MVT::f64) {
1928 LocVT = MVT::i64;
1929 LocInfo = CCValAssign::BCvt;
1930 } else if (UseGPRForFloat && GRLen == 32 && ValVT == MVT::f64) {
1931 // TODO: Handle passing f64 on LA32 with D feature.
1932 report_fatal_error("Passing f64 with GPR on LA32 is undefined");
1933 }
1934
1935 // If this is a variadic argument, the LoongArch calling convention requires
1936 // that it is assigned an 'even' or 'aligned' register if it has (2*GRLen)/8
1937 // byte alignment. An aligned register should be used regardless of whether
1938 // the original argument was split during legalisation or not. The argument
1939 // will not be passed by registers if the original type is larger than
1940 // 2*GRLen, so the register alignment rule does not apply.
1941 unsigned TwoGRLenInBytes = (2 * GRLen) / 8;
1942 if (!IsFixed && ArgFlags.getNonZeroOrigAlign() == TwoGRLenInBytes &&
1943 DL.getTypeAllocSize(OrigTy) == TwoGRLenInBytes) {
1944 unsigned RegIdx = State.getFirstUnallocated(ArgGPRs);
1945 // Skip 'odd' register if necessary.
1946 if (RegIdx != std::size(ArgGPRs) && RegIdx % 2 == 1)
1947 State.AllocateReg(ArgGPRs);
1948 }
1949
1950 SmallVectorImpl<CCValAssign> &PendingLocs = State.getPendingLocs();
1951 SmallVectorImpl<ISD::ArgFlagsTy> &PendingArgFlags =
1952 State.getPendingArgFlags();
1953
1954 assert(PendingLocs.size() == PendingArgFlags.size() &&
1955 "PendingLocs and PendingArgFlags out of sync");
1956
1957 // Split arguments might be passed indirectly, so keep track of the pending
1958 // values.
1959 if (ValVT.isScalarInteger() && (ArgFlags.isSplit() || !PendingLocs.empty())) {
1960 LocVT = GRLenVT;
1961 LocInfo = CCValAssign::Indirect;
1962 PendingLocs.push_back(
1963 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo));
1964 PendingArgFlags.push_back(ArgFlags);
1965 if (!ArgFlags.isSplitEnd()) {
1966 return false;
1967 }
1968 }
1969
1970 // If the split argument only had two elements, it should be passed directly
1971 // in registers or on the stack.
1972 if (ValVT.isScalarInteger() && ArgFlags.isSplitEnd() &&
1973 PendingLocs.size() <= 2) {
1974 assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()");
1975 // Apply the normal calling convention rules to the first half of the
1976 // split argument.
1977 CCValAssign VA = PendingLocs[0];
1978 ISD::ArgFlagsTy AF = PendingArgFlags[0];
1979 PendingLocs.clear();
1980 PendingArgFlags.clear();
1981 return CC_LoongArchAssign2GRLen(GRLen, State, VA, AF, ValNo, ValVT, LocVT,
1982 ArgFlags);
1983 }
1984
1985 // Allocate to a register if possible, or else a stack slot.
1986 Register Reg;
1987 unsigned StoreSizeBytes = GRLen / 8;
1988 Align StackAlign = Align(GRLen / 8);
1989
1990 if (ValVT == MVT::f32 && !UseGPRForFloat)
1991 Reg = State.AllocateReg(ArgFPR32s);
1992 else if (ValVT == MVT::f64 && !UseGPRForFloat)
1993 Reg = State.AllocateReg(ArgFPR64s);
1994 else
1995 Reg = State.AllocateReg(ArgGPRs);
1996
1997 unsigned StackOffset =
1998 Reg ? 0 : State.AllocateStack(StoreSizeBytes, StackAlign);
1999
2000 // If we reach this point and PendingLocs is non-empty, we must be at the
2001 // end of a split argument that must be passed indirectly.
2002 if (!PendingLocs.empty()) {
2003 assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()");
2004 assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()");
2005 for (auto &It : PendingLocs) {
2006 if (Reg)
2007 It.convertToReg(Reg);
2008 else
2009 It.convertToMem(StackOffset);
2010 State.addLoc(It);
2011 }
2012 PendingLocs.clear();
2013 PendingArgFlags.clear();
2014 return false;
2015 }
2016 assert((!UseGPRForFloat || LocVT == GRLenVT) &&
2017 "Expected an GRLenVT at this stage");
2018
2019 if (Reg) {
2020 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2021 return false;
2022 }
2023
2024 // When a floating-point value is passed on the stack, no bit-cast is needed.
2025 if (ValVT.isFloatingPoint()) {
2026 LocVT = ValVT;
2027 LocInfo = CCValAssign::Full;
2028 }
2029
2030 State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
2031 return false;
2032}
2033
2034void LoongArchTargetLowering::analyzeInputArgs(
2035 MachineFunction &MF, CCState &CCInfo,
2036 const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
2037 LoongArchCCAssignFn Fn) const {
2039 for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
2040 MVT ArgVT = Ins[i].VT;
2041 Type *ArgTy = nullptr;
2042 if (IsRet)
2043 ArgTy = FType->getReturnType();
2044 else if (Ins[i].isOrigArg())
2045 ArgTy = FType->getParamType(Ins[i].getOrigArgIndex());
2048 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Ins[i].Flags,
2049 CCInfo, /*IsFixed=*/true, IsRet, ArgTy)) {
2050 LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
2051 << ArgVT << '\n');
2052 llvm_unreachable("");
2053 }
2054 }
2055}
2056
2057void LoongArchTargetLowering::analyzeOutputArgs(
2058 MachineFunction &MF, CCState &CCInfo,
2059 const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsRet,
2060 CallLoweringInfo *CLI, LoongArchCCAssignFn Fn) const {
2061 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2062 MVT ArgVT = Outs[i].VT;
2063 Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr;
2066 if (Fn(MF.getDataLayout(), ABI, i, ArgVT, CCValAssign::Full, Outs[i].Flags,
2067 CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) {
2068 LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
2069 << ArgVT << "\n");
2070 llvm_unreachable("");
2071 }
2072 }
2073}
2074
2075// Convert Val to a ValVT. Should not be called for CCValAssign::Indirect
2076// values.
2078 const CCValAssign &VA, const SDLoc &DL) {
2079 switch (VA.getLocInfo()) {
2080 default:
2081 llvm_unreachable("Unexpected CCValAssign::LocInfo");
2082 case CCValAssign::Full:
2084 break;
2085 case CCValAssign::BCvt:
2086 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2088 else
2089 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val);
2090 break;
2091 }
2092 return Val;
2093}
2094
2096 const CCValAssign &VA, const SDLoc &DL,
2097 const LoongArchTargetLowering &TLI) {
2100 EVT LocVT = VA.getLocVT();
2101 SDValue Val;
2102 const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
2103 Register VReg = RegInfo.createVirtualRegister(RC);
2104 RegInfo.addLiveIn(VA.getLocReg(), VReg);
2105 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
2106
2107 return convertLocVTToValVT(DAG, Val, VA, DL);
2108}
2109
2110// The caller is responsible for loading the full value if the argument is
2111// passed with CCValAssign::Indirect.
2113 const CCValAssign &VA, const SDLoc &DL) {
2115 MachineFrameInfo &MFI = MF.getFrameInfo();
2116 EVT ValVT = VA.getValVT();
2117 int FI = MFI.CreateFixedObject(ValVT.getStoreSize(), VA.getLocMemOffset(),
2118 /*IsImmutable=*/true);
2119 SDValue FIN = DAG.getFrameIndex(
2121
2122 ISD::LoadExtType ExtType;
2123 switch (VA.getLocInfo()) {
2124 default:
2125 llvm_unreachable("Unexpected CCValAssign::LocInfo");
2126 case CCValAssign::Full:
2128 case CCValAssign::BCvt:
2129 ExtType = ISD::NON_EXTLOAD;
2130 break;
2131 }
2132 return DAG.getExtLoad(
2133 ExtType, DL, VA.getLocVT(), Chain, FIN,
2135}
2136
2138 const CCValAssign &VA, const SDLoc &DL) {
2139 EVT LocVT = VA.getLocVT();
2140
2141 switch (VA.getLocInfo()) {
2142 default:
2143 llvm_unreachable("Unexpected CCValAssign::LocInfo");
2144 case CCValAssign::Full:
2145 break;
2146 case CCValAssign::BCvt:
2147 if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32)
2149 else
2150 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val);
2151 break;
2152 }
2153 return Val;
2154}
2155
2156static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT,
2157 CCValAssign::LocInfo LocInfo,
2158 ISD::ArgFlagsTy ArgFlags, CCState &State) {
2159 if (LocVT == MVT::i32 || LocVT == MVT::i64) {
2160 // Pass in STG registers: Base, Sp, Hp, R1, R2, R3, R4, R5, SpLim
2161 // s0 s1 s2 s3 s4 s5 s6 s7 s8
2162 static const MCPhysReg GPRList[] = {
2163 LoongArch::R23, LoongArch::R24, LoongArch::R25, LoongArch::R26, LoongArch::R27,
2164 LoongArch::R28, LoongArch::R29, LoongArch::R30, LoongArch::R31};
2165 if (unsigned Reg = State.AllocateReg(GPRList)) {
2166 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2167 return false;
2168 }
2169 }
2170
2171 if (LocVT == MVT::f32) {
2172 // Pass in STG registers: F1, F2, F3, F4
2173 // fs0,fs1,fs2,fs3
2174 static const MCPhysReg FPR32List[] = {LoongArch::F24, LoongArch::F25,
2175 LoongArch::F26, LoongArch::F27};
2176 if (unsigned Reg = State.AllocateReg(FPR32List)) {
2177 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2178 return false;
2179 }
2180 }
2181
2182 if (LocVT == MVT::f64) {
2183 // Pass in STG registers: D1, D2, D3, D4
2184 // fs4,fs5,fs6,fs7
2185 static const MCPhysReg FPR64List[] = {LoongArch::F28_64, LoongArch::F29_64,
2186 LoongArch::F30_64, LoongArch::F31_64};
2187 if (unsigned Reg = State.AllocateReg(FPR64List)) {
2188 State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
2189 return false;
2190 }
2191 }
2192
2193 report_fatal_error("No registers left in GHC calling convention");
2194 return true;
2195}
2196
2197// Transform physical registers into virtual registers.
2199 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2200 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
2201 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
2202
2204
2205 switch (CallConv) {
2206 default:
2207 llvm_unreachable("Unsupported calling convention");
2208 case CallingConv::C:
2209 case CallingConv::Fast:
2210 break;
2211 case CallingConv::GHC:
2212 if (!MF.getSubtarget().hasFeature(LoongArch::FeatureBasicF) ||
2213 !MF.getSubtarget().hasFeature(LoongArch::FeatureBasicD))
2215 "GHC calling convention requires the F and D extensions");
2216 }
2217
2218 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2219 MVT GRLenVT = Subtarget.getGRLenVT();
2220 unsigned GRLenInBytes = Subtarget.getGRLen() / 8;
2221 // Used with varargs to acumulate store chains.
2222 std::vector<SDValue> OutChains;
2223
2224 // Assign locations to all of the incoming arguments.
2226 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2227
2228 if (CallConv == CallingConv::GHC)
2230 else
2231 analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false, CC_LoongArch);
2232
2233 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
2234 CCValAssign &VA = ArgLocs[i];
2235 SDValue ArgValue;
2236 if (VA.isRegLoc())
2237 ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL, *this);
2238 else
2239 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL);
2240 if (VA.getLocInfo() == CCValAssign::Indirect) {
2241 // If the original argument was split and passed by reference, we need to
2242 // load all parts of it here (using the same address).
2243 InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue,
2245 unsigned ArgIndex = Ins[i].OrigArgIndex;
2246 unsigned ArgPartOffset = Ins[i].PartOffset;
2247 assert(ArgPartOffset == 0);
2248 while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) {
2249 CCValAssign &PartVA = ArgLocs[i + 1];
2250 unsigned PartOffset = Ins[i + 1].PartOffset - ArgPartOffset;
2251 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2252 SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, Offset);
2253 InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address,
2255 ++i;
2256 }
2257 continue;
2258 }
2259 InVals.push_back(ArgValue);
2260 }
2261
2262 if (IsVarArg) {
2264 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
2265 const TargetRegisterClass *RC = &LoongArch::GPRRegClass;
2266 MachineFrameInfo &MFI = MF.getFrameInfo();
2267 MachineRegisterInfo &RegInfo = MF.getRegInfo();
2268 auto *LoongArchFI = MF.getInfo<LoongArchMachineFunctionInfo>();
2269
2270 // Offset of the first variable argument from stack pointer, and size of
2271 // the vararg save area. For now, the varargs save area is either zero or
2272 // large enough to hold a0-a7.
2273 int VaArgOffset, VarArgsSaveSize;
2274
2275 // If all registers are allocated, then all varargs must be passed on the
2276 // stack and we don't need to save any argregs.
2277 if (ArgRegs.size() == Idx) {
2278 VaArgOffset = CCInfo.getNextStackOffset();
2279 VarArgsSaveSize = 0;
2280 } else {
2281 VarArgsSaveSize = GRLenInBytes * (ArgRegs.size() - Idx);
2282 VaArgOffset = -VarArgsSaveSize;
2283 }
2284
2285 // Record the frame index of the first variable argument
2286 // which is a value necessary to VASTART.
2287 int FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2288 LoongArchFI->setVarArgsFrameIndex(FI);
2289
2290 // If saving an odd number of registers then create an extra stack slot to
2291 // ensure that the frame pointer is 2*GRLen-aligned, which in turn ensures
2292 // offsets to even-numbered registered remain 2*GRLen-aligned.
2293 if (Idx % 2) {
2294 MFI.CreateFixedObject(GRLenInBytes, VaArgOffset - (int)GRLenInBytes,
2295 true);
2296 VarArgsSaveSize += GRLenInBytes;
2297 }
2298
2299 // Copy the integer registers that may have been used for passing varargs
2300 // to the vararg save area.
2301 for (unsigned I = Idx; I < ArgRegs.size();
2302 ++I, VaArgOffset += GRLenInBytes) {
2303 const Register Reg = RegInfo.createVirtualRegister(RC);
2304 RegInfo.addLiveIn(ArgRegs[I], Reg);
2305 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, GRLenVT);
2306 FI = MFI.CreateFixedObject(GRLenInBytes, VaArgOffset, true);
2307 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2308 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff,
2310 cast<StoreSDNode>(Store.getNode())
2311 ->getMemOperand()
2312 ->setValue((Value *)nullptr);
2313 OutChains.push_back(Store);
2314 }
2315 LoongArchFI->setVarArgsSaveSize(VarArgsSaveSize);
2316 }
2317
2318 // All stores are grouped in one node to allow the matching between
2319 // the size of Ins and InVals. This only happens for vararg functions.
2320 if (!OutChains.empty()) {
2321 OutChains.push_back(Chain);
2322 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
2323 }
2324
2325 return Chain;
2326}
2327
2329 return CI->isTailCall();
2330}
2331
2332// Check if the return value is used as only a return value, as otherwise
2333// we can't perform a tail-call.
2335 SDValue &Chain) const {
2336 if (N->getNumValues() != 1)
2337 return false;
2338 if (!N->hasNUsesOfValue(1, 0))
2339 return false;
2340
2341 SDNode *Copy = *N->use_begin();
2342 if (Copy->getOpcode() != ISD::CopyToReg)
2343 return false;
2344
2345 // If the ISD::CopyToReg has a glue operand, we conservatively assume it
2346 // isn't safe to perform a tail call.
2347 if (Copy->getGluedNode())
2348 return false;
2349
2350 // The copy must be used by a LoongArchISD::RET, and nothing else.
2351 bool HasRet = false;
2352 for (SDNode *Node : Copy->uses()) {
2353 if (Node->getOpcode() != LoongArchISD::RET)
2354 return false;
2355 HasRet = true;
2356 }
2357
2358 if (!HasRet)
2359 return false;
2360
2361 Chain = Copy->getOperand(0);
2362 return true;
2363}
2364
2365// Check whether the call is eligible for tail call optimization.
2366bool LoongArchTargetLowering::isEligibleForTailCallOptimization(
2367 CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF,
2368 const SmallVectorImpl<CCValAssign> &ArgLocs) const {
2369
2370 auto CalleeCC = CLI.CallConv;
2371 auto &Outs = CLI.Outs;
2372 auto &Caller = MF.getFunction();
2373 auto CallerCC = Caller.getCallingConv();
2374
2375 // Do not tail call opt if the stack is used to pass parameters.
2376 if (CCInfo.getNextStackOffset() != 0)
2377 return false;
2378
2379 // Do not tail call opt if any parameters need to be passed indirectly.
2380 for (auto &VA : ArgLocs)
2381 if (VA.getLocInfo() == CCValAssign::Indirect)
2382 return false;
2383
2384 // Do not tail call opt if either caller or callee uses struct return
2385 // semantics.
2386 auto IsCallerStructRet = Caller.hasStructRetAttr();
2387 auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
2388 if (IsCallerStructRet || IsCalleeStructRet)
2389 return false;
2390
2391 // Do not tail call opt if either the callee or caller has a byval argument.
2392 for (auto &Arg : Outs)
2393 if (Arg.Flags.isByVal())
2394 return false;
2395
2396 // The callee has to preserve all registers the caller needs to preserve.
2397 const LoongArchRegisterInfo *TRI = Subtarget.getRegisterInfo();
2398 const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC);
2399 if (CalleeCC != CallerCC) {
2400 const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC);
2401 if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved))
2402 return false;
2403 }
2404 return true;
2405}
2406
2408 return DAG.getDataLayout().getPrefTypeAlign(
2409 VT.getTypeForEVT(*DAG.getContext()));
2410}
2411
2412// Lower a call to a callseq_start + CALL + callseq_end chain, and add input
2413// and output parameter nodes.
2414SDValue
2416 SmallVectorImpl<SDValue> &InVals) const {
2417 SelectionDAG &DAG = CLI.DAG;
2418 SDLoc &DL = CLI.DL;
2420 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
2422 SDValue Chain = CLI.Chain;
2423 SDValue Callee = CLI.Callee;
2424 CallingConv::ID CallConv = CLI.CallConv;
2425 bool IsVarArg = CLI.IsVarArg;
2426 EVT PtrVT = getPointerTy(DAG.getDataLayout());
2427 MVT GRLenVT = Subtarget.getGRLenVT();
2428 bool &IsTailCall = CLI.IsTailCall;
2429
2431
2432 // Analyze the operands of the call, assigning locations to each operand.
2434 CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
2435
2436 if (CallConv == CallingConv::GHC)
2437 ArgCCInfo.AnalyzeCallOperands(Outs, CC_LoongArch_GHC);
2438 else
2439 analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI, CC_LoongArch);
2440
2441 // Check if it's really possible to do a tail call.
2442 if (IsTailCall)
2443 IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs);
2444
2445 if (IsTailCall)
2446 ++NumTailCalls;
2447 else if (CLI.CB && CLI.CB->isMustTailCall())
2448 report_fatal_error("failed to perform tail call elimination on a call "
2449 "site marked musttail");
2450
2451 // Get a count of how many bytes are to be pushed on the stack.
2452 unsigned NumBytes = ArgCCInfo.getNextStackOffset();
2453
2454 // Create local copies for byval args.
2455 SmallVector<SDValue> ByValArgs;
2456 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2457 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2458 if (!Flags.isByVal())
2459 continue;
2460
2461 SDValue Arg = OutVals[i];
2462 unsigned Size = Flags.getByValSize();
2463 Align Alignment = Flags.getNonZeroByValAlign();
2464
2465 int FI =
2466 MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false);
2467 SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout()));
2468 SDValue SizeNode = DAG.getConstant(Size, DL, GRLenVT);
2469
2470 Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment,
2471 /*IsVolatile=*/false,
2472 /*AlwaysInline=*/false, /*isTailCall=*/IsTailCall,
2474 ByValArgs.push_back(FIPtr);
2475 }
2476
2477 if (!IsTailCall)
2478 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL);
2479
2480 // Copy argument values to their designated locations.
2482 SmallVector<SDValue> MemOpChains;
2483 SDValue StackPtr;
2484 for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) {
2485 CCValAssign &VA = ArgLocs[i];
2486 SDValue ArgValue = OutVals[i];
2487 ISD::ArgFlagsTy Flags = Outs[i].Flags;
2488
2489 // Promote the value if needed.
2490 // For now, only handle fully promoted and indirect arguments.
2491 if (VA.getLocInfo() == CCValAssign::Indirect) {
2492 // Store the argument in a stack slot and pass its address.
2493 Align StackAlign =
2494 std::max(getPrefTypeAlign(Outs[i].ArgVT, DAG),
2495 getPrefTypeAlign(ArgValue.getValueType(), DAG));
2496 TypeSize StoredSize = ArgValue.getValueType().getStoreSize();
2497 // If the original argument was split and passed by reference, we need to
2498 // store the required parts of it here (and pass just one address).
2499 unsigned ArgIndex = Outs[i].OrigArgIndex;
2500 unsigned ArgPartOffset = Outs[i].PartOffset;
2501 assert(ArgPartOffset == 0);
2502 // Calculate the total size to store. We don't have access to what we're
2503 // actually storing other than performing the loop and collecting the
2504 // info.
2506 while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) {
2507 SDValue PartValue = OutVals[i + 1];
2508 unsigned PartOffset = Outs[i + 1].PartOffset - ArgPartOffset;
2509 SDValue Offset = DAG.getIntPtrConstant(PartOffset, DL);
2510 EVT PartVT = PartValue.getValueType();
2511
2512 StoredSize += PartVT.getStoreSize();
2513 StackAlign = std::max(StackAlign, getPrefTypeAlign(PartVT, DAG));
2514 Parts.push_back(std::make_pair(PartValue, Offset));
2515 ++i;
2516 }
2517 SDValue SpillSlot = DAG.CreateStackTemporary(StoredSize, StackAlign);
2518 int FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
2519 MemOpChains.push_back(
2520 DAG.getStore(Chain, DL, ArgValue, SpillSlot,
2522 for (const auto &Part : Parts) {
2523 SDValue PartValue = Part.first;
2524 SDValue PartOffset = Part.second;
2526 DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, PartOffset);
2527 MemOpChains.push_back(
2528 DAG.getStore(Chain, DL, PartValue, Address,
2530 }
2531 ArgValue = SpillSlot;
2532 } else {
2533 ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL);
2534 }
2535
2536 // Use local copy if it is a byval arg.
2537 if (Flags.isByVal())
2538 ArgValue = ByValArgs[j++];
2539
2540 if (VA.isRegLoc()) {
2541 // Queue up the argument copies and emit them at the end.
2542 RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue));
2543 } else {
2544 assert(VA.isMemLoc() && "Argument not register or memory");
2545 assert(!IsTailCall && "Tail call not allowed if stack is used "
2546 "for passing parameters");
2547
2548 // Work out the address of the stack slot.
2549 if (!StackPtr.getNode())
2550 StackPtr = DAG.getCopyFromReg(Chain, DL, LoongArch::R3, PtrVT);
2552 DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr,
2554
2555 // Emit the store.
2556 MemOpChains.push_back(
2557 DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo()));
2558 }
2559 }
2560
2561 // Join the stores, which are independent of one another.
2562 if (!MemOpChains.empty())
2563 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
2564
2565 SDValue Glue;
2566
2567 // Build a sequence of copy-to-reg nodes, chained and glued together.
2568 for (auto &Reg : RegsToPass) {
2569 Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue);
2570 Glue = Chain.getValue(1);
2571 }
2572
2573 // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a
2574 // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't
2575 // split it and then direct call can be matched by PseudoCALL.
2576 if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) {
2577 const GlobalValue *GV = S->getGlobal();
2578 unsigned OpFlags =
2582 Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, OpFlags);
2583 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
2584 unsigned OpFlags = getTargetMachine().shouldAssumeDSOLocal(
2585 *MF.getFunction().getParent(), nullptr)
2588 Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags);
2589 }
2590
2591 // The first call operand is the chain and the second is the target address.
2593 Ops.push_back(Chain);
2594 Ops.push_back(Callee);
2595
2596 // Add argument registers to the end of the list so that they are
2597 // known live into the call.
2598 for (auto &Reg : RegsToPass)
2599 Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
2600
2601 if (!IsTailCall) {
2602 // Add a register mask operand representing the call-preserved registers.
2603 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
2604 const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv);
2605 assert(Mask && "Missing call preserved mask for calling convention");
2606 Ops.push_back(DAG.getRegisterMask(Mask));
2607 }
2608
2609 // Glue the call to the argument copies, if any.
2610 if (Glue.getNode())
2611 Ops.push_back(Glue);
2612
2613 // Emit the call.
2614 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
2615
2616 if (IsTailCall) {
2618 return DAG.getNode(LoongArchISD::TAIL, DL, NodeTys, Ops);
2619 }
2620
2621 Chain = DAG.getNode(LoongArchISD::CALL, DL, NodeTys, Ops);
2622 DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge);
2623 Glue = Chain.getValue(1);
2624
2625 // Mark the end of the call, which is glued to the call itself.
2626 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL);
2627 Glue = Chain.getValue(1);
2628
2629 // Assign locations to each value returned by this call.
2631 CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext());
2632 analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true, CC_LoongArch);
2633
2634 // Copy all of the result registers out of their specified physreg.
2635 for (auto &VA : RVLocs) {
2636 // Copy the value out.
2637 SDValue RetValue =
2638 DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue);
2639 // Glue the RetValue to the end of the call sequence.
2640 Chain = RetValue.getValue(1);
2641 Glue = RetValue.getValue(2);
2642
2643 RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL);
2644
2645 InVals.push_back(RetValue);
2646 }
2647
2648 return Chain;
2649}
2650
2652 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
2653 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
2655 CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
2656
2657 for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
2658 LoongArchABI::ABI ABI =
2659 MF.getSubtarget<LoongArchSubtarget>().getTargetABI();
2660 if (CC_LoongArch(MF.getDataLayout(), ABI, i, Outs[i].VT, CCValAssign::Full,
2661 Outs[i].Flags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true,
2662 nullptr))
2663 return false;
2664 }
2665 return true;
2666}
2667
2669 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
2671 const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
2672 SelectionDAG &DAG) const {
2673 // Stores the assignment of the return value to a location.
2675
2676 // Info about the registers and stack slot.
2677 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
2678 *DAG.getContext());
2679
2680 analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true,
2681 nullptr, CC_LoongArch);
2682 if (CallConv == CallingConv::GHC && !RVLocs.empty())
2683 report_fatal_error("GHC functions return void only");
2684 SDValue Glue;
2685 SmallVector<SDValue, 4> RetOps(1, Chain);
2686
2687 // Copy the result values into the output registers.
2688 for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
2689 CCValAssign &VA = RVLocs[i];
2690 assert(VA.isRegLoc() && "Can only return in registers!");
2691
2692 // Handle a 'normal' return.
2693 SDValue Val = convertValVTToLocVT(DAG, OutVals[i], VA, DL);
2694 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue);
2695
2696 // Guarantee that all emitted copies are stuck together.
2697 Glue = Chain.getValue(1);
2698 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
2699 }
2700
2701 RetOps[0] = Chain; // Update chain.
2702
2703 // Add the glue node if we have it.
2704 if (Glue.getNode())
2705 RetOps.push_back(Glue);
2706
2707 return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
2708}
2709
2710bool LoongArchTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
2711 bool ForCodeSize) const {
2712 // TODO: Maybe need more checks here after vector extension is supported.
2713 if (VT == MVT::f32 && !Subtarget.hasBasicF())
2714 return false;
2715 if (VT == MVT::f64 && !Subtarget.hasBasicD())
2716 return false;
2717 return (Imm.isZero() || Imm.isExactlyValue(+1.0));
2718}
2719
2721 return true;
2722}
2723
2725 return true;
2726}
2727
2728bool LoongArchTargetLowering::shouldInsertFencesForAtomic(
2729 const Instruction *I) const {
2730 if (!Subtarget.is64Bit())
2731 return isa<LoadInst>(I) || isa<StoreInst>(I);
2732
2733 if (isa<LoadInst>(I))
2734 return true;
2735
2736 // On LA64, atomic store operations with IntegerBitWidth of 32 and 64 do not
2737 // require fences beacuse we can use amswap_db.[w/d].
2738 if (isa<StoreInst>(I)) {
2739 unsigned Size = I->getOperand(0)->getType()->getIntegerBitWidth();
2740 return (Size == 8 || Size == 16);
2741 }
2742
2743 return false;
2744}
2745
2747 LLVMContext &Context,
2748 EVT VT) const {
2749 if (!VT.isVector())
2750 return getPointerTy(DL);
2752}
2753
2755 // TODO: Support vectors.
2756 return Y.getValueType().isScalarInteger() && !isa<ConstantSDNode>(Y);
2757}
2758
2760 const CallInst &I,
2761 MachineFunction &MF,
2762 unsigned Intrinsic) const {
2763 switch (Intrinsic) {
2764 default:
2765 return false;
2766 case Intrinsic::loongarch_masked_atomicrmw_xchg_i32:
2767 case Intrinsic::loongarch_masked_atomicrmw_add_i32:
2768 case Intrinsic::loongarch_masked_atomicrmw_sub_i32:
2769 case Intrinsic::loongarch_masked_atomicrmw_nand_i32:
2771 Info.memVT = MVT::i32;
2772 Info.ptrVal = I.getArgOperand(0);
2773 Info.offset = 0;
2774 Info.align = Align(4);
2777 return true;
2778 // TODO: Add more Intrinsics later.
2779 }
2780}
2781
2784 // TODO: Add more AtomicRMWInst that needs to be extended.
2785
2786 // Since floating-point operation requires a non-trivial set of data
2787 // operations, use CmpXChg to expand.
2788 if (AI->isFloatingPointOperation() ||
2792
2793 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
2794 if (Size == 8 || Size == 16)
2797}
2798
2799static Intrinsic::ID
2801 AtomicRMWInst::BinOp BinOp) {
2802 if (GRLen == 64) {
2803 switch (BinOp) {
2804 default:
2805 llvm_unreachable("Unexpected AtomicRMW BinOp");
2807 return Intrinsic::loongarch_masked_atomicrmw_xchg_i64;
2808 case AtomicRMWInst::Add:
2809 return Intrinsic::loongarch_masked_atomicrmw_add_i64;
2810 case AtomicRMWInst::Sub:
2811 return Intrinsic::loongarch_masked_atomicrmw_sub_i64;
2813 return Intrinsic::loongarch_masked_atomicrmw_nand_i64;
2815 return Intrinsic::loongarch_masked_atomicrmw_umax_i64;
2817 return Intrinsic::loongarch_masked_atomicrmw_umin_i64;
2818 case AtomicRMWInst::Max:
2819 return Intrinsic::loongarch_masked_atomicrmw_max_i64;
2820 case AtomicRMWInst::Min:
2821 return Intrinsic::loongarch_masked_atomicrmw_min_i64;
2822 // TODO: support other AtomicRMWInst.
2823 }
2824 }
2825
2826 if (GRLen == 32) {
2827 switch (BinOp) {
2828 default:
2829 llvm_unreachable("Unexpected AtomicRMW BinOp");
2831 return Intrinsic::loongarch_masked_atomicrmw_xchg_i32;
2832 case AtomicRMWInst::Add:
2833 return Intrinsic::loongarch_masked_atomicrmw_add_i32;
2834 case AtomicRMWInst::Sub:
2835 return Intrinsic::loongarch_masked_atomicrmw_sub_i32;
2837 return Intrinsic::loongarch_masked_atomicrmw_nand_i32;
2838 // TODO: support other AtomicRMWInst.
2839 }
2840 }
2841
2842 llvm_unreachable("Unexpected GRLen\n");
2843}
2844
2847 AtomicCmpXchgInst *CI) const {
2849 if (Size == 8 || Size == 16)
2852}
2853
2855 IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr,
2856 Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const {
2857 Value *Ordering =
2858 Builder.getIntN(Subtarget.getGRLen(), static_cast<uint64_t>(Ord));
2859
2860 // TODO: Support cmpxchg on LA32.
2861 Intrinsic::ID CmpXchgIntrID = Intrinsic::loongarch_masked_cmpxchg_i64;
2862 CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty());
2863 NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty());
2864 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2865 Type *Tys[] = {AlignedAddr->getType()};
2866 Function *MaskedCmpXchg =
2867 Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys);
2868 Value *Result = Builder.CreateCall(
2869 MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering});
2870 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2871 return Result;
2872}
2873
2875 IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr,
2876 Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const {
2877 unsigned GRLen = Subtarget.getGRLen();
2878 Value *Ordering =
2879 Builder.getIntN(GRLen, static_cast<uint64_t>(AI->getOrdering()));
2880 Type *Tys[] = {AlignedAddr->getType()};
2881 Function *LlwOpScwLoop = Intrinsic::getDeclaration(
2882 AI->getModule(),
2884
2885 if (GRLen == 64) {
2886 Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty());
2887 Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty());
2888 ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty());
2889 }
2890
2891 Value *Result;
2892
2893 // Must pass the shift amount needed to sign extend the loaded value prior
2894 // to performing a signed comparison for min/max. ShiftAmt is the number of
2895 // bits to shift the value into position. Pass GRLen-ShiftAmt-ValWidth, which
2896 // is the number of bits to left+right shift the value in order to
2897 // sign-extend.
2898 if (AI->getOperation() == AtomicRMWInst::Min ||
2900 const DataLayout &DL = AI->getModule()->getDataLayout();
2901 unsigned ValWidth =
2902 DL.getTypeStoreSizeInBits(AI->getValOperand()->getType());
2903 Value *SextShamt =
2904 Builder.CreateSub(Builder.getIntN(GRLen, GRLen - ValWidth), ShiftAmt);
2905 Result = Builder.CreateCall(LlwOpScwLoop,
2906 {AlignedAddr, Incr, Mask, SextShamt, Ordering});
2907 } else {
2908 Result =
2909 Builder.CreateCall(LlwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering});
2910 }
2911
2912 if (GRLen == 64)
2913 Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
2914 return Result;
2915}
2916
2918 const MachineFunction &MF, EVT VT) const {
2919 VT = VT.getScalarType();
2920
2921 if (!VT.isSimple())
2922 return false;
2923
2924 switch (VT.getSimpleVT().SimpleTy) {
2925 case MVT::f32:
2926 case MVT::f64:
2927 return true;
2928 default:
2929 break;
2930 }
2931
2932 return false;
2933}
2934
2936 const Constant *PersonalityFn) const {
2937 return LoongArch::R4;
2938}
2939
2941 const Constant *PersonalityFn) const {
2942 return LoongArch::R5;
2943}
2944
2945//===----------------------------------------------------------------------===//
2946// LoongArch Inline Assembly Support
2947//===----------------------------------------------------------------------===//
2948
2950LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
2951 // LoongArch specific constraints in GCC: config/loongarch/constraints.md
2952 //
2953 // 'f': A floating-point register (if available).
2954 // 'k': A memory operand whose address is formed by a base register and
2955 // (optionally scaled) index register.
2956 // 'l': A signed 16-bit constant.
2957 // 'm': A memory operand whose address is formed by a base register and
2958 // offset that is suitable for use in instructions with the same
2959 // addressing mode as st.w and ld.w.
2960 // 'I': A signed 12-bit constant (for arithmetic instructions).
2961 // 'J': Integer zero.
2962 // 'K': An unsigned 12-bit constant (for logic instructions).
2963 // "ZB": An address that is held in a general-purpose register. The offset is
2964 // zero.
2965 // "ZC": A memory operand whose address is formed by a base register and
2966 // offset that is suitable for use in instructions with the same
2967 // addressing mode as ll.w and sc.w.
2968 if (Constraint.size() == 1) {
2969 switch (Constraint[0]) {
2970 default:
2971 break;
2972 case 'f':
2973 return C_RegisterClass;
2974 case 'l':
2975 case 'I':
2976 case 'J':
2977 case 'K':
2978 return C_Immediate;
2979 case 'k':
2980 return C_Memory;
2981 }
2982 }
2983
2984 if (Constraint == "ZC" || Constraint == "ZB")
2985 return C_Memory;
2986
2987 // 'm' is handled here.
2988 return TargetLowering::getConstraintType(Constraint);
2989}
2990
2991unsigned LoongArchTargetLowering::getInlineAsmMemConstraint(
2992 StringRef ConstraintCode) const {
2993 return StringSwitch<unsigned>(ConstraintCode)
2998}
2999
3000std::pair<unsigned, const TargetRegisterClass *>
3001LoongArchTargetLowering::getRegForInlineAsmConstraint(
3002 const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
3003 // First, see if this is a constraint that directly corresponds to a LoongArch
3004 // register class.
3005 if (Constraint.size() == 1) {
3006 switch (Constraint[0]) {
3007 case 'r':
3008 // TODO: Support fixed vectors up to GRLen?
3009 if (VT.isVector())
3010 break;
3011 return std::make_pair(0U, &LoongArch::GPRRegClass);
3012 case 'f':
3013 if (Subtarget.hasBasicF() && VT == MVT::f32)
3014 return std::make_pair(0U, &LoongArch::FPR32RegClass);
3015 if (Subtarget.hasBasicD() && VT == MVT::f64)
3016 return std::make_pair(0U, &LoongArch::FPR64RegClass);
3017 break;
3018 default:
3019 break;
3020 }
3021 }
3022
3023 // TargetLowering::getRegForInlineAsmConstraint uses the name of the TableGen
3024 // record (e.g. the "R0" in `def R0`) to choose registers for InlineAsm
3025 // constraints while the official register name is prefixed with a '$'. So we
3026 // clip the '$' from the original constraint string (e.g. {$r0} to {r0}.)
3027 // before it being parsed. And TargetLowering::getRegForInlineAsmConstraint is
3028 // case insensitive, so no need to convert the constraint to upper case here.
3029 //
3030 // For now, no need to support ABI names (e.g. `$a0`) as clang will correctly
3031 // decode the usage of register name aliases into their official names. And
3032 // AFAIK, the not yet upstreamed `rustc` for LoongArch will always use
3033 // official register names.
3034 if (Constraint.startswith("{$r") || Constraint.startswith("{$f")) {
3035 bool IsFP = Constraint[2] == 'f';
3036 std::pair<StringRef, StringRef> Temp = Constraint.split('$');
3037 std::pair<unsigned, const TargetRegisterClass *> R;
3039 TRI, join_items("", Temp.first, Temp.second), VT);
3040 // Match those names to the widest floating point register type available.
3041 if (IsFP) {
3042 unsigned RegNo = R.first;
3043 if (LoongArch::F0 <= RegNo && RegNo <= LoongArch::F31) {
3044 if (Subtarget.hasBasicD() && (VT == MVT::f64 || VT == MVT::Other)) {
3045 unsigned DReg = RegNo - LoongArch::F0 + LoongArch::F0_64;
3046 return std::make_pair(DReg, &LoongArch::FPR64RegClass);
3047 }
3048 }
3049 }
3050 return R;
3051 }
3052
3053 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
3054}
3055
3056void LoongArchTargetLowering::LowerAsmOperandForConstraint(
3057 SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops,
3058 SelectionDAG &DAG) const {
3059 // Currently only support length 1 constraints.
3060 if (Constraint.length() == 1) {
3061 switch (Constraint[0]) {
3062 case 'l':
3063 // Validate & create a 16-bit signed immediate operand.
3064 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3065 uint64_t CVal = C->getSExtValue();
3066 if (isInt<16>(CVal))
3067 Ops.push_back(
3068 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3069 }
3070 return;
3071 case 'I':
3072 // Validate & create a 12-bit signed immediate operand.
3073 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3074 uint64_t CVal = C->getSExtValue();
3075 if (isInt<12>(CVal))
3076 Ops.push_back(
3077 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3078 }
3079 return;
3080 case 'J':
3081 // Validate & create an integer zero operand.
3082 if (auto *C = dyn_cast<ConstantSDNode>(Op))
3083 if (C->getZExtValue() == 0)
3084 Ops.push_back(
3085 DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getGRLenVT()));
3086 return;
3087 case 'K':
3088 // Validate & create a 12-bit unsigned immediate operand.
3089 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
3090 uint64_t CVal = C->getZExtValue();
3091 if (isUInt<12>(CVal))
3092 Ops.push_back(
3093 DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getGRLenVT()));
3094 }
3095 return;
3096 default:
3097 break;
3098 }
3099 }
3100 TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
3101}
3102
3103#define GET_REGISTER_MATCHER
3104#include "LoongArchGenAsmMatcher.inc"
3105
3108 const MachineFunction &MF) const {
3109 std::pair<StringRef, StringRef> Name = StringRef(RegName).split('$');
3110 std::string NewRegName = Name.second.str();
3111 Register Reg = MatchRegisterAltName(NewRegName);
3112 if (Reg == LoongArch::NoRegister)
3113 Reg = MatchRegisterName(NewRegName);
3114 if (Reg == LoongArch::NoRegister)
3116 Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
3117 BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF);
3118 if (!ReservedRegs.test(Reg))
3119 report_fatal_error(Twine("Trying to obtain non-reserved register \"" +
3120 StringRef(RegName) + "\"."));
3121 return Reg;
3122}
3123
3125 EVT VT, SDValue C) const {
3126 // TODO: Support vectors.
3127 if (!VT.isScalarInteger())
3128 return false;
3129
3130 // Omit the optimization if the data size exceeds GRLen.
3131 if (VT.getSizeInBits() > Subtarget.getGRLen())
3132 return false;
3133
3134 // Break MUL into (SLLI + ADD/SUB) or ALSL.
3135 if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) {
3136 const APInt &Imm = ConstNode->getAPIntValue();
3137 if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() ||
3138 (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2())
3139 return true;
3140 }
3141
3142 return false;
3143}
3144
3146 const AddrMode &AM,
3147 Type *Ty, unsigned AS,
3148 Instruction *I) const {
3149 // LoongArch has four basic addressing modes:
3150 // 1. reg
3151 // 2. reg + 12-bit signed offset
3152 // 3. reg + 14-bit signed offset left-shifted by 2
3153 // 4. reg1 + reg2
3154 // TODO: Add more checks after support vector extension.
3155
3156 // No global is ever allowed as a base.
3157 if (AM.BaseGV)
3158 return false;
3159
3160 // Require a 12 or 14 bit signed offset.
3161 if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs))
3162 return false;
3163
3164 switch (AM.Scale) {
3165 case 0:
3166 // "i" is not allowed.
3167 if (!AM.HasBaseReg)
3168 return false;
3169 // Otherwise we have "r+i".
3170 break;
3171 case 1:
3172 // "r+r+i" is not allowed.
3173 if (AM.HasBaseReg && AM.BaseOffs != 0)
3174 return false;
3175 // Otherwise we have "r+r" or "r+i".
3176 break;
3177 case 2:
3178 // "2*r+r" or "2*r+i" is not allowed.
3179 if (AM.HasBaseReg || AM.BaseOffs)
3180 return false;
3181 // Otherwise we have "r+r".
3182 break;
3183 default:
3184 return false;
3185 }
3186
3187 return true;
3188}
3189
3191 // TODO: Support vectors.
3192 if (Y.getValueType().isVector())
3193 return false;
3194
3195 return !isa<ConstantSDNode>(Y);
3196}
static unsigned MatchRegisterName(StringRef Name)
static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const AArch64Subtarget *Subtarget, const AArch64TargetLowering &TLI)
static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI)
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define NODE_NAME_CASE(node)
amdgpu Simplify well known AMD library false FunctionCallee Callee
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
static unsigned MatchRegisterAltName(StringRef Name)
Maps from the set of all alternative registernames to a register number.
Function Alias Analysis Results
assume Assume Builder
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL)
static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#define LLVM_DEBUG(X)
Definition: Debug.h:101
uint64_t Addr
std::string Name
uint64_t Size
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define RegName(no)
const MCPhysReg ArgFPR32s[]
static SDValue emitIntrinsicErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static cl::opt< bool > ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false))
static Align getPrefTypeAlign(EVT VT, SelectionDAG &DAG)
static bool CC_LoongArch(const DataLayout &DL, LoongArchABI::ABI ABI, unsigned ValNo, MVT ValVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy)
static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define CRC_CASE_EXT_BINARYOP(NAME, NODE)
static MachineBasicBlock * insertDivByZeroTrap(MachineInstr &MI, MachineBasicBlock *MBB)
static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, unsigned Flags)
static bool CC_LoongArch_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State)
static SDValue emitIntrinsicWithChainErrorMessage(SDValue Op, StringRef ErrorMsg, SelectionDAG &DAG)
static bool CC_LoongArchAssign2GRLen(unsigned GRLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2)
const MCPhysReg ArgFPR64s[]
#define IOCSRWR_CASE(NAME, NODE)
#define CRC_CASE_EXT_UNARYOP(NAME, NODE)
const MCPhysReg ArgGPRs[]
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG, int NumOp, unsigned ExtOpc=ISD::ANY_EXTEND)
#define ASRT_LE_GT_CASE(NAME)
static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const LoongArchSubtarget &Subtarget)
#define IOCSRRD_CASE(NAME, NODE)
#define CSR_CASE(ID)
static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned GRLen, AtomicRMWInst::BinOp BinOp)
static LoongArchISD::NodeType getLoongArchWOpcode(unsigned Opcode)
#define I(x, y, z)
Definition: MD5.cpp:58
unsigned const TargetRegisterInfo * TRI
typename CallsiteContextGraph< DerivedCCG, FuncTy, CallTy >::FuncInfo FuncInfo
LLVMContext & Context
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const char LLVMTargetMachineRef TM
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition: Statistic.h:167
@ Flags
Definition: TextStubV5.cpp:93
Class for arbitrary precision integers.
Definition: APInt.h:75
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition: APInt.h:1235
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:163
An instruction that atomically checks whether a specified value is in a memory location,...
Definition: Instructions.h:513
an instruction that atomically reads a memory location, combines it with another value,...
Definition: Instructions.h:718
BinOp
This enumeration lists the possible modifications atomicrmw can make.
Definition: Instructions.h:730
@ Add
*p = old + v
Definition: Instructions.h:734
@ Min
*p = old <signed v ? old : v
Definition: Instructions.h:748
@ Sub
*p = old - v
Definition: Instructions.h:736
@ UIncWrap
Increment one up to a maximum value.
Definition: Instructions.h:770
@ Max
*p = old >signed v ? old : v
Definition: Instructions.h:746
@ UMin
*p = old <unsigned v ? old : v
Definition: Instructions.h:752
@ UMax
*p = old >unsigned v ? old : v
Definition: Instructions.h:750
@ UDecWrap
Decrement one until a minimum value or zero.
Definition: Instructions.h:774
@ Nand
*p = ~(old & v)
Definition: Instructions.h:740
bool isFloatingPointOperation() const
Definition: Instructions.h:889
BinOp getOperation() const
Definition: Instructions.h:812
Value * getValOperand()
Definition: Instructions.h:881
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
Definition: Instructions.h:854
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
bool test(unsigned Idx) const
Definition: BitVector.h:461
CCState - This class holds information needed while lowering arguments and return values.
unsigned getFirstUnallocated(ArrayRef< MCPhysReg > Regs) const
getFirstUnallocated - Return the index of the first unallocated register in the set,...
unsigned AllocateStack(unsigned Size, Align Alignment)
AllocateStack - Allocate a chunk of stack space with the specified size and alignment.
unsigned getNextStackOffset() const
getNextStackOffset - Return the next stack offset such that all stack slots satisfy their alignment r...
SmallVectorImpl< ISD::ArgFlagsTy > & getPendingArgFlags()
MCRegister AllocateReg(MCPhysReg Reg)
AllocateReg - Attempt to allocate one register.
void AnalyzeCallOperands(const SmallVectorImpl< ISD::OutputArg > &Outs, CCAssignFn Fn)
AnalyzeCallOperands - Analyze the outgoing arguments to a call, incorporating info about the passed v...
SmallVectorImpl< CCValAssign > & getPendingLocs()
void AnalyzeFormalArguments(const SmallVectorImpl< ISD::InputArg > &Ins, CCAssignFn Fn)
AnalyzeFormalArguments - Analyze an array of argument values, incorporating info about the formals in...
void addLoc(const CCValAssign &V)
CCValAssign - Represent assignment of one arg/retval to a location.
bool isRegLoc() const
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT, LocInfo HTP, unsigned ExtraInfo=0)
unsigned getLocMemOffset() const
Register getLocReg() const
LocInfo getLocInfo() const
static CCValAssign getReg(unsigned ValNo, MVT ValVT, unsigned RegNo, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool isMemLoc() const
unsigned getValNo() const
static CCValAssign getMem(unsigned ValNo, MVT ValVT, unsigned Offset, MVT LocVT, LocInfo HTP, bool IsCustom=false)
bool isMustTailCall() const
Tests if this call site must be tail call optimized.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
uint64_t getZExtValue() const
int64_t getSExtValue() const
This is an important base class in LLVM.
Definition: Constant.h:41
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:110
unsigned getPointerSizeInBits(unsigned AS=0) const
Layout pointer size, in bits FIXME: The defaults need to be removed once all of the backends/clients ...
Definition: DataLayout.h:406
Align getPrefTypeAlign(Type *Ty) const
Returns the preferred stack/global alignment for the specified type.
Definition: DataLayout.cpp:857
A debug info location.
Definition: DebugLoc.h:33
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:174
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition: Function.h:237
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:652
Common base class shared among various IRBuilders.
Definition: IRBuilder.h:94
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Definition: Instruction.cpp:70
Class to represent integer types.
Definition: DerivedTypes.h:40
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
void emitError(uint64_t LocCookie, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
LoongArchMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private Lo...
const LoongArchRegisterInfo * getRegisterInfo() const override
const LoongArchInstrInfo * getInstrInfo() const override
bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override
Return true if result of the specified node is used by a return node only.
SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override
This method will be invoked for all target nodes and for any target-independent nodes that the target...
TargetLowering::AtomicExpansionKind shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *CI) const override
Returns how the given atomic cmpxchg should be expanded by the IR-level AtomicExpand pass.
Value * emitMaskedAtomicCmpXchgIntrinsic(IRBuilderBase &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const override
Perform a masked cmpxchg using a target-specific intrinsic.
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override
Return the ValueType of the result of SETCC operations.
bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, EVT VT) const override
Return true if an FMA operation is faster than a pair of fmul and fadd instructions.
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower calls into the specified DAG.
bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override
Return true if it is profitable to transform an integer multiplication-by-constant into simpler opera...
TargetLowering::AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
bool isCheapToSpeculateCtlz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic ctlz.
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
Value * emitMaskedAtomicRMWIntrinsic(IRBuilderBase &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const override
Perform a masked atomicrmw using a target-specific intrinsic.
Register getExceptionPointerRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception address on entry to an ...
const char * getTargetNodeName(unsigned Opcode) const override
This method returns the name of a target specific DAG node.
bool getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool isCheapToSpeculateCttz(Type *Ty) const override
Return true if it is cheap to speculate a call to intrinsic cttz.
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I=nullptr) const override
Return true if the addressing mode represented by AM is legal for this target, for a load/store of th...
Register getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const override
Return the register ID of the name passed in.
bool hasAndNot(SDValue Y) const override
Return true if the target has a bitwise and-not operation: X = ~A & B This can be used to simplify se...
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override
Return true if folding a constant offset with the given GlobalAddress is legal.
bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, LLVMContext &Context) const override
This hook should be implemented to check whether the return values described by the Outs array can fi...
Register getExceptionSelectorRegister(const Constant *PersonalityFn) const override
If a physical register, this returns the register that receives the exception typeid on entry to a la...
void ReplaceNodeResults(SDNode *N, SmallVectorImpl< SDValue > &Results, SelectionDAG &DAG) const override
This callback is invoked when a node result type is illegal for the target, and the operation was reg...
LoongArchTargetLowering(const TargetMachine &TM, const LoongArchSubtarget &STI)
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::OutputArg > &Outs, const SmallVectorImpl< SDValue > &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override
This hook must be implemented to lower outgoing return values, described by the Outs array,...
bool hasAndNotCompare(SDValue Y) const override
Return true if the target should transform: (X & Y) == Y —> (~X & Y) == 0 (X & Y) !...
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl< ISD::InputArg > &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl< SDValue > &InVals) const override
This hook must be implemented to lower the incoming (formal) arguments, described by the Ins array,...
bool mayBeEmittedAsTailCall(const CallInst *CI) const override
Return true if the target may be able emit the call instruction as a tail call.
bool hasFeature(unsigned Feature) const
Machine Value Type.
SimpleValueType SimpleTy
bool isVector() const
Return true if this is a vector value type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable, bool isAliased=false)
Create a new object at a fixed location on the stack.
int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
void setFrameAddressIsTaken(bool T)
void setHasTailCall(bool V=true)
void setReturnAddressIsTaken(bool s)
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *bb=nullptr)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Register addLiveIn(MCRegister PReg, const TargetRegisterClass *RC)
addLiveIn - Add the specified physical register as a live-in value and create a corresponding virtual...
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
Definition: MachineInstr.h:68
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:526
@ MOVolatile
The memory access is volatile.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void addLiveIn(MCRegister Reg, Register vreg=Register())
addLiveIn - Add the specified register as a live-in.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
Definition: Module.cpp:398
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
const SDValue & getOperand(unsigned Num) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
uint64_t getConstantOperandVal(unsigned i) const
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
Definition: SelectionDAG.h:225
SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
SDValue getTargetGlobalAddress(const GlobalValue *GV, const SDLoc &DL, EVT VT, int64_t offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:721
SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false)
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr)
Loads are not normal binary operators: their result type is not determined by their operands,...
void addNoMergeSiteInfo(const SDNode *Node, bool NoMerge)
Set NoMergeSiteInfo to be associated with Node if NoMerge is true.
const TargetLowering & getTargetLoweringInfo() const
Definition: SelectionDAG.h:478
SDValue getTargetJumpTable(int JTI, EVT VT, unsigned TargetFlags=0)
Definition: SelectionDAG.h:731
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, SDValue InGlue, const SDLoc &DL)
Return a new CALLSEQ_END node, which always must have a glue result (to ensure it's not CSE'd).
SDValue getMemcpy(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, bool isTailCall, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo=AAMDNodes(), AAResults *AA=nullptr)
const DataLayout & getDataLayout() const
Definition: SelectionDAG.h:472
SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
Helper function to build ISD::STORE nodes.
SDValue getCALLSEQ_START(SDValue Chain, uint64_t InSize, uint64_t OutSize, const SDLoc &DL)
Return a new CALLSEQ_START node, that starts new call frame, in which InSize bytes are set up inside ...
SDValue getRegister(unsigned Reg, EVT VT)
SDValue getExternalSymbol(const char *Sym, EVT VT)
SDValue getCopyToReg(SDValue Chain, const SDLoc &dl, unsigned Reg, SDValue N)
Definition: SelectionDAG.h:773
SDValue getIntPtrConstant(uint64_t Val, const SDLoc &DL, bool isTarget=false)
SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
Definition: SelectionDAG.h:675
SDValue getTargetBlockAddress(const BlockAddress *BA, EVT VT, int64_t Offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:768
MachineFunction & getMachineFunction() const
Definition: SelectionDAG.h:469
SDValue getCopyFromReg(SDValue Chain, const SDLoc &dl, unsigned Reg, EVT VT)
Definition: SelectionDAG.h:799
SDValue getFrameIndex(int FI, EVT VT, bool isTarget=false)
KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
SDValue getRegisterMask(const uint32_t *RegMask)
LLVMContext * getContext() const
Definition: SelectionDAG.h:485
SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)
SDValue CreateStackTemporary(TypeSize Bytes, Align Alignment)
Create a stack temporary based on the size in bytes and the alignment.
SDValue getTargetConstantPool(const Constant *C, EVT VT, MaybeAlign Align=std::nullopt, int Offset=0, unsigned TargetFlags=0)
Definition: SelectionDAG.h:737
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
Definition: SelectionDAG.h:554
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:577
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StackOffset holds a fixed and a scalable offset in bytes.
Definition: TypeSize.h:36
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:687
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
TargetInstrInfo - Interface to description of machine instruction set.
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
const TargetMachine & getTargetMachine() const
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
void setMinFunctionAlignment(Align Alignment)
Set the target's minimum function alignment.
void setBooleanContents(BooleanContent Ty)
Specify how the target extends the result of integer and floating point boolean values from i1 to a w...
void computeRegisterProperties(const TargetRegisterInfo *TRI)
Once all of the register classes are added, this allows us to compute derived properties we expose.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setLibcallName(RTLIB::Libcall Call, const char *Name)
Rename the default libcall routine name for the specified libcall.
void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified truncating store does not work with the specified type and indicate what ...
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
void setStackPointerRegisterToSaveRestore(Register R)
If set to a physical register, this specifies the register that llvm.savestack/llvm....
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
void setLoadExtAction(unsigned ExtType, MVT ValVT, MVT MemVT, LegalizeAction Action)
Indicate that the specified load with extension does not work with the specified type and indicate wh...
LegalizeTypeAction getTypeAction(LLVMContext &Context, EVT VT) const
Return how we should legalize values of this type, either it is already legal (return 'Legal') or we ...
std::vector< ArgListEntry > ArgListTy
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
std::pair< SDValue, SDValue > makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef< SDValue > Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue Chain=SDValue()) const
Returns a pair of (return value, chain).
virtual void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector< SDValue > &Ops, SelectionDAG &DAG) const
Lower the specified operand into the Ops vector.
virtual ConstraintType getConstraintType(StringRef Constraint) const
Given a constraint, return the type of constraint it is for this target.
virtual unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const
std::pair< SDValue, SDValue > LowerCallTo(CallLoweringInfo &CLI) const
This function lowers an abstract call to a function into an actual call.
virtual std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const
Given a physical register constraint (e.g.
bool verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:78
bool shouldAssumeDSOLocal(const Module &M, const GlobalValue *GV) const
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
self_iterator getIterator()
Definition: ilist_node.h:82
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ GHC
Used by the Glasgow Haskell Compiler (GHC).
Definition: CallingConv.h:50
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition: CallingConv.h:41
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
Definition: ISDOpcodes.h:1069
@ STACKSAVE
STACKSAVE - STACKSAVE has one operand, an input chain.
Definition: ISDOpcodes.h:1065
@ STRICT_FSETCC
STRICT_FSETCC/STRICT_FSETCCS - Constrained versions of SETCC, used for floating-point operands only.
Definition: ISDOpcodes.h:475
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition: ISDOpcodes.h:250
@ BSWAP
Byte Swap and Counting operators.
Definition: ISDOpcodes.h:713
@ VAEND
VAEND, VASTART - VAEND and VASTART have three operands: an input chain, pointer, and a SRCVALUE.
Definition: ISDOpcodes.h:1098
@ FMAXNUM_IEEE
Definition: ISDOpcodes.h:963
@ ADD
Simple integer binary arithmetic operators.
Definition: ISDOpcodes.h:239
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition: ISDOpcodes.h:779
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition: ISDOpcodes.h:482
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition: ISDOpcodes.h:199
@ RETURNADDR
Definition: ISDOpcodes.h:95
@ GlobalAddress
Definition: ISDOpcodes.h:78
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition: ISDOpcodes.h:786
@ STRICT_FSETCCS
Definition: ISDOpcodes.h:476
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
Definition: ISDOpcodes.h:898
@ GlobalTLSAddress
Definition: ISDOpcodes.h:79
@ WRITE_REGISTER
Definition: ISDOpcodes.h:119
@ FSINCOS
FSINCOS - Compute both fsin and fcos as a single operation.
Definition: ISDOpcodes.h:972
@ BR_CC
BR_CC - Conditional branch.
Definition: ISDOpcodes.h:1020
@ BR_JT
BR_JT - Jumptable branch.
Definition: ISDOpcodes.h:1003
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition: ISDOpcodes.h:726
@ VACOPY
VACOPY - VACOPY has 5 operands: an input chain, a destination pointer, a source pointer,...
Definition: ISDOpcodes.h:1094
@ SHL
Shift and rotation operations.
Definition: ISDOpcodes.h:704
@ FMINNUM_IEEE
FMINNUM_IEEE/FMAXNUM_IEEE - Perform floating-point minimum or maximum on two values,...
Definition: ISDOpcodes.h:962
@ READ_REGISTER
READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on the DAG, which implements the n...
Definition: ISDOpcodes.h:118
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition: ISDOpcodes.h:203
@ DEBUGTRAP
DEBUGTRAP - Trap intended to get the attention of a debugger.
Definition: ISDOpcodes.h:1148
@ SELECT_CC
Select with condition operator - This selects between a true value and a false value (ops #2 and #3) ...
Definition: ISDOpcodes.h:741
@ DYNAMIC_STACKALLOC
DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned to a specified boundary.
Definition: ISDOpcodes.h:988
@ ConstantPool
Definition: ISDOpcodes.h:82
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition: ISDOpcodes.h:794
@ EH_DWARF_CFA
EH_DWARF_CFA - This node represents the pointer to the DWARF Canonical Frame Address (CFA),...
Definition: ISDOpcodes.h:129
@ FRAMEADDR
FRAMEADDR, RETURNADDR - These nodes represent llvm.frameaddress and llvm.returnaddress on the DAG.
Definition: ISDOpcodes.h:94
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition: ISDOpcodes.h:832
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition: ISDOpcodes.h:679
@ TRAP
TRAP - Trapping instruction.
Definition: ISDOpcodes.h:1145
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition: ISDOpcodes.h:184
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition: ISDOpcodes.h:52
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition: ISDOpcodes.h:782
@ VAARG
VAARG - VAARG has four operands: an input chain, a pointer, a SRCVALUE, and the alignment.
Definition: ISDOpcodes.h:1089
@ BlockAddress
Definition: ISDOpcodes.h:84
@ SHL_PARTS
SHL_PARTS/SRA_PARTS/SRL_PARTS - These operators are used for expanded integer shift operations.
Definition: ISDOpcodes.h:762
@ AssertSext
AssertSext, AssertZext - These nodes record if a register contains a value that has already been zero...
Definition: ISDOpcodes.h:61
@ AssertZext
Definition: ISDOpcodes.h:62
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition: ISDOpcodes.h:192
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
Definition: ISDOpcodes.h:1447
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
Definition: ISDOpcodes.h:1427
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1506
ABI getTargetABI(StringRef ABIName)
Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Libcall
RTLIB::Libcall enum - This enum defines all of the runtime library calls the backend can emit.
Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
@ GeneralDynamic
Definition: CodeGen.h:46
Reg
All possible values of the reg field in the ModR/M byte.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:406
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr bool isShiftedMask_64(uint64_t Value)
Return true if the argument contains a non-empty sequence of ones with the remainder zero (64 bit ver...
Definition: MathExtras.h:286
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
AtomicOrdering
Atomic ordering for LLVM's memory model.
unsigned getKillRegState(bool B)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
Extended Value Type.
Definition: ValueTypes.h:34
EVT changeVectorElementTypeToInteger() const
Return a vector with the same number of elements as this vector, but with the element type converted ...
Definition: ValueTypes.h:93
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
Definition: ValueTypes.h:373
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition: ValueTypes.h:129
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition: ValueTypes.h:351
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition: ValueTypes.h:299
static EVT getFloatingPointVT(unsigned BitWidth)
Returns the EVT that represents a floating-point type with the given number of bits.
Definition: ValueTypes.h:58
bool isVector() const
Return true if this is a vector value type.
Definition: ValueTypes.h:160
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition: ValueTypes.h:306
Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
Definition: ValueTypes.cpp:194
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition: ValueTypes.h:149
Align getNonZeroOrigAlign() const
Register getFrameRegister(const MachineFunction &MF) const override
BitVector getReservedRegs(const MachineFunction &MF) const override
This class contains a discriminated union of information about pointers in memory operands,...
static MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
Definition: <