1//===----------------------------------------------------------------------===//
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#include "RISCVSelectionDAGInfo.h"
10#include "RISCVSubtarget.h"
11#include "llvm/CodeGen/SelectionDAG.h"
12
13#define GET_SDNODE_DESC
14#include "RISCVGenSDNodeInfo.inc"
15
16using namespace llvm;
17
18RISCVSelectionDAGInfo::RISCVSelectionDAGInfo()
19 : SelectionDAGGenTargetInfo(RISCVGenSDNodeInfo) {}
20
21RISCVSelectionDAGInfo::~RISCVSelectionDAGInfo() = default;
22
23void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
24 const SDNode *N) const {
25 SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
26
27#ifndef NDEBUG
28 // Some additional checks not yet implemented by verifyTargetNode.
29 switch (N->getOpcode()) {
30 case RISCVISD::TUPLE_EXTRACT:
31 assert(N->getOperand(1).getOpcode() == ISD::TargetConstant &&
32 "Expected index to be a target constant!");
33 break;
34 case RISCVISD::TUPLE_INSERT:
35 assert(N->getOperand(2).getOpcode() == ISD::TargetConstant &&
36 "Expected index to be a target constant!");
37 break;
38 case RISCVISD::VQDOT_VL:
39 case RISCVISD::VQDOTU_VL:
40 case RISCVISD::VQDOTSU_VL: {
41 EVT VT = N->getValueType(0);
42 assert(VT.isScalableVector() && VT.getVectorElementType() == MVT::i32 &&
43 "Expected result to be an i32 scalable vector");
44 assert(N->getOperand(0).getValueType() == VT &&
45 N->getOperand(1).getValueType() == VT &&
46 N->getOperand(2).getValueType() == VT &&
47 "Expected result and first 3 operands to have the same type!");
48 EVT MaskVT = N->getOperand(3).getValueType();
49 assert(MaskVT.isScalableVector() &&
50 MaskVT.getVectorElementCount() == VT.getVectorElementCount() &&
51 "Expected mask VT to be an i1 scalable vector with same number of "
52 "elements as the result");
53 break;
54 }
55 }
56#endif
57}
58
59SDValue RISCVSelectionDAGInfo::EmitTargetCodeForMemset(
60 SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src,
61 SDValue Size, Align Alignment, bool isVolatile, bool AlwaysInline,
62 MachinePointerInfo DstPtrInfo) const {
63 const auto &Subtarget = DAG.getSubtarget<RISCVSubtarget>();
64 // We currently do this only for Xqcilsm
65 if (!Subtarget.hasVendorXqcilsm())
66 return SDValue();
67
68 // Do this only if we know the size at compile time.
69 ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Val&: Size);
70 if (!ConstantSize)
71 return SDValue();
72
73 uint64_t NumberOfBytesToWrite = ConstantSize->getZExtValue();
74
75 // Do this only if it is word aligned and we write a multiple of 4 bytes.
76 if (!(Alignment >= 4) || !((NumberOfBytesToWrite & 3) == 0))
77 return SDValue();
78
79 SmallVector<SDValue, 8> OutChains;
80 SDValue SrcValueReplicated = DAG.getNode(Opcode: ISD::ZERO_EXTEND, DL: dl, VT: MVT::i32, Operand: Src);
81 int NumberOfWords = NumberOfBytesToWrite / 4;
82 MachineFunction &MF = DAG.getMachineFunction();
83 auto Volatile =
84 isVolatile ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone;
85
86 // Helper for constructing the QC_SETWMI instruction
87 auto getSetwmiNode = [&](uint8_t SizeWords, uint8_t OffsetSetwmi) -> SDValue {
88 SDValue Ops[] = {Chain, SrcValueReplicated, Dst,
89 DAG.getTargetConstant(Val: SizeWords, DL: dl, VT: MVT::i32),
90 DAG.getTargetConstant(Val: OffsetSetwmi, DL: dl, VT: MVT::i32)};
91 MachineMemOperand *BaseMemOperand = MF.getMachineMemOperand(
92 PtrInfo: DstPtrInfo.getWithOffset(O: OffsetSetwmi),
93 F: MachineMemOperand::MOStore | Volatile, Size: SizeWords * 4, BaseAlignment: Align(4));
94 return DAG.getMemIntrinsicNode(Opcode: RISCVISD::QC_SETWMI, dl,
95 VTList: DAG.getVTList(VT: MVT::Other), Ops, MemVT: MVT::i32,
96 MMO: BaseMemOperand);
97 };
98
99 // If i8 type and constant non-zero value.
100 if ((Src.getValueType() == MVT::i8) && !isNullConstant(V: Src))
101 // Replicate byte to word by multiplication with 0x01010101.
102 SrcValueReplicated =
103 DAG.getNode(Opcode: ISD::MUL, DL: dl, VT: MVT::i32, N1: SrcValueReplicated,
104 N2: DAG.getConstant(Val: 0x01010101ul, DL: dl, VT: MVT::i32));
105
106 // We limit a QC_SETWMI to 16 words or less to improve interruptibility.
107 // So for 1-16 words we use a single QC_SETWMI:
108 //
109 // QC_SETWMI reg1, N, 0(reg2)
110 //
111 // For 17-32 words we use two QC_SETWMI's with the first as 16 words and the
112 // second for the remainder:
113 //
114 // QC_SETWMI reg1, 16, 0(reg2)
115 // QC_SETWMI reg1, N, 64(reg2)
116 //
117 // For 33-48 words, we would like to use (16, 16, n), but that means the last
118 // QC_SETWMI needs an offset of 128 which the instruction doesn't support.
119 // So in this case we use a length of 15 for the second instruction and we do
120 // the rest with the third instruction.
121 // This means the maximum inlined number of words is 47 (for now):
122 //
123 // QC_SETWMI R2, R0, 16, 0
124 // QC_SETWMI R2, R0, 15, 64
125 // QC_SETWMI R2, R0, N, 124
126 //
127 // For 48 words or more, call the target independent memset
128 if (NumberOfWords >= 48)
129 return SDValue();
130
131 if (NumberOfWords <= 16) {
132 // 1 - 16 words
133 return getSetwmiNode(NumberOfWords, 0);
134 }
135
136 if (NumberOfWords <= 32) {
137 // 17 - 32 words
138 OutChains.push_back(Elt: getSetwmiNode(NumberOfWords - 16, 64));
139 OutChains.push_back(Elt: getSetwmiNode(16, 0));
140 } else {
141 // 33 - 47 words
142 OutChains.push_back(Elt: getSetwmiNode(NumberOfWords - 31, 124));
143 OutChains.push_back(Elt: getSetwmiNode(15, 64));
144 OutChains.push_back(Elt: getSetwmiNode(16, 0));
145 }
146
147 return DAG.getNode(Opcode: ISD::TokenFactor, DL: dl, VT: MVT::Other, Ops: OutChains);
148}
149