18
18
#include " LoongArchSubtarget.h"
19
19
#include " LoongArchTargetMachine.h"
20
20
#include " llvm/ADT/Statistic.h"
21
+ #include " llvm/CodeGen/ISDOpcodes.h"
21
22
#include " llvm/Support/Debug.h"
22
23
23
24
using namespace llvm ;
@@ -37,6 +38,29 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
37
38
addRegisterClass (MVT::f64 , &LoongArch::FPR64RegClass);
38
39
39
40
// TODO: add necessary setOperationAction calls later.
41
+ setOperationAction (ISD::SHL_PARTS, GRLenVT, Custom);
42
+ setOperationAction (ISD::SRA_PARTS, GRLenVT, Custom);
43
+ setOperationAction (ISD::SRL_PARTS, GRLenVT, Custom);
44
+
45
+ if (Subtarget.is64Bit ()) {
46
+ setOperationAction (ISD::SHL, MVT::i32 , Custom);
47
+ setOperationAction (ISD::SRA, MVT::i32 , Custom);
48
+ setOperationAction (ISD::SRL, MVT::i32 , Custom);
49
+ }
50
+
51
+ static const ISD::CondCode FPCCToExpand[] = {ISD::SETOGT, ISD::SETOGE,
52
+ ISD::SETUGT, ISD::SETUGE};
53
+
54
+ if (Subtarget.hasBasicF ()) {
55
+ setCondCodeAction (FPCCToExpand, MVT::f32 , Expand);
56
+ setOperationAction (ISD::SELECT_CC, MVT::f32 , Expand);
57
+ }
58
+ if (Subtarget.hasBasicD ()) {
59
+ setCondCodeAction (FPCCToExpand, MVT::f64 , Expand);
60
+ setOperationAction (ISD::SELECT_CC, MVT::f64 , Expand);
61
+ }
62
+
63
+ setOperationAction (ISD::SELECT_CC, GRLenVT, Expand);
40
64
41
65
// Compute derived properties from the register classes.
42
66
computeRegisterProperties (STI.getRegisterInfo ());
@@ -50,6 +74,169 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
50
74
setMinFunctionAlignment (FunctionAlignment);
51
75
}
52
76
77
+ SDValue LoongArchTargetLowering::LowerOperation (SDValue Op,
78
+ SelectionDAG &DAG) const {
79
+ switch (Op.getOpcode ()) {
80
+ default :
81
+ report_fatal_error (" unimplemented operand" );
82
+ case ISD::SHL_PARTS:
83
+ return lowerShiftLeftParts (Op, DAG);
84
+ case ISD::SRA_PARTS:
85
+ return lowerShiftRightParts (Op, DAG, true );
86
+ case ISD::SRL_PARTS:
87
+ return lowerShiftRightParts (Op, DAG, false );
88
+ case ISD::SHL:
89
+ case ISD::SRA:
90
+ case ISD::SRL:
91
+ // This can be called for an i32 shift amount that needs to be promoted.
92
+ assert (Op.getOperand (1 ).getValueType () == MVT::i32 && Subtarget.is64Bit () &&
93
+ " Unexpected custom legalisation" );
94
+ return SDValue ();
95
+ }
96
+ }
97
+
98
+ SDValue LoongArchTargetLowering::lowerShiftLeftParts (SDValue Op,
99
+ SelectionDAG &DAG) const {
100
+ SDLoc DL (Op);
101
+ SDValue Lo = Op.getOperand (0 );
102
+ SDValue Hi = Op.getOperand (1 );
103
+ SDValue Shamt = Op.getOperand (2 );
104
+ EVT VT = Lo.getValueType ();
105
+
106
+ // if Shamt-GRLen < 0: // Shamt < GRLen
107
+ // Lo = Lo << Shamt
108
+ // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (GRLen-1 ^ Shamt))
109
+ // else:
110
+ // Lo = 0
111
+ // Hi = Lo << (Shamt-GRLen)
112
+
113
+ SDValue Zero = DAG.getConstant (0 , DL, VT);
114
+ SDValue One = DAG.getConstant (1 , DL, VT);
115
+ SDValue MinusGRLen = DAG.getConstant (-(int )Subtarget.getGRLen (), DL, VT);
116
+ SDValue GRLenMinus1 = DAG.getConstant (Subtarget.getGRLen () - 1 , DL, VT);
117
+ SDValue ShamtMinusGRLen = DAG.getNode (ISD::ADD, DL, VT, Shamt, MinusGRLen);
118
+ SDValue GRLenMinus1Shamt = DAG.getNode (ISD::XOR, DL, VT, Shamt, GRLenMinus1);
119
+
120
+ SDValue LoTrue = DAG.getNode (ISD::SHL, DL, VT, Lo, Shamt);
121
+ SDValue ShiftRight1Lo = DAG.getNode (ISD::SRL, DL, VT, Lo, One);
122
+ SDValue ShiftRightLo =
123
+ DAG.getNode (ISD::SRL, DL, VT, ShiftRight1Lo, GRLenMinus1Shamt);
124
+ SDValue ShiftLeftHi = DAG.getNode (ISD::SHL, DL, VT, Hi, Shamt);
125
+ SDValue HiTrue = DAG.getNode (ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo);
126
+ SDValue HiFalse = DAG.getNode (ISD::SHL, DL, VT, Lo, ShamtMinusGRLen);
127
+
128
+ SDValue CC = DAG.getSetCC (DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
129
+
130
+ Lo = DAG.getNode (ISD::SELECT, DL, VT, CC, LoTrue, Zero);
131
+ Hi = DAG.getNode (ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
132
+
133
+ SDValue Parts[2 ] = {Lo, Hi};
134
+ return DAG.getMergeValues (Parts, DL);
135
+ }
136
+
137
+ SDValue LoongArchTargetLowering::lowerShiftRightParts (SDValue Op,
138
+ SelectionDAG &DAG,
139
+ bool IsSRA) const {
140
+ SDLoc DL (Op);
141
+ SDValue Lo = Op.getOperand (0 );
142
+ SDValue Hi = Op.getOperand (1 );
143
+ SDValue Shamt = Op.getOperand (2 );
144
+ EVT VT = Lo.getValueType ();
145
+
146
+ // SRA expansion:
147
+ // if Shamt-GRLen < 0: // Shamt < GRLen
148
+ // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
149
+ // Hi = Hi >>s Shamt
150
+ // else:
151
+ // Lo = Hi >>s (Shamt-GRLen);
152
+ // Hi = Hi >>s (GRLen-1)
153
+ //
154
+ // SRL expansion:
155
+ // if Shamt-GRLen < 0: // Shamt < GRLen
156
+ // Lo = (Lo >>u Shamt) | ((Hi << 1) << (ShAmt ^ GRLen-1))
157
+ // Hi = Hi >>u Shamt
158
+ // else:
159
+ // Lo = Hi >>u (Shamt-GRLen);
160
+ // Hi = 0;
161
+
162
+ unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL;
163
+
164
+ SDValue Zero = DAG.getConstant (0 , DL, VT);
165
+ SDValue One = DAG.getConstant (1 , DL, VT);
166
+ SDValue MinusGRLen = DAG.getConstant (-(int )Subtarget.getGRLen (), DL, VT);
167
+ SDValue GRLenMinus1 = DAG.getConstant (Subtarget.getGRLen () - 1 , DL, VT);
168
+ SDValue ShamtMinusGRLen = DAG.getNode (ISD::ADD, DL, VT, Shamt, MinusGRLen);
169
+ SDValue GRLenMinus1Shamt = DAG.getNode (ISD::XOR, DL, VT, Shamt, GRLenMinus1);
170
+
171
+ SDValue ShiftRightLo = DAG.getNode (ISD::SRL, DL, VT, Lo, Shamt);
172
+ SDValue ShiftLeftHi1 = DAG.getNode (ISD::SHL, DL, VT, Hi, One);
173
+ SDValue ShiftLeftHi =
174
+ DAG.getNode (ISD::SHL, DL, VT, ShiftLeftHi1, GRLenMinus1Shamt);
175
+ SDValue LoTrue = DAG.getNode (ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi);
176
+ SDValue HiTrue = DAG.getNode (ShiftRightOp, DL, VT, Hi, Shamt);
177
+ SDValue LoFalse = DAG.getNode (ShiftRightOp, DL, VT, Hi, ShamtMinusGRLen);
178
+ SDValue HiFalse =
179
+ IsSRA ? DAG.getNode (ISD::SRA, DL, VT, Hi, GRLenMinus1) : Zero;
180
+
181
+ SDValue CC = DAG.getSetCC (DL, VT, ShamtMinusGRLen, Zero, ISD::SETLT);
182
+
183
+ Lo = DAG.getNode (ISD::SELECT, DL, VT, CC, LoTrue, LoFalse);
184
+ Hi = DAG.getNode (ISD::SELECT, DL, VT, CC, HiTrue, HiFalse);
185
+
186
+ SDValue Parts[2 ] = {Lo, Hi};
187
+ return DAG.getMergeValues (Parts, DL);
188
+ }
189
+
190
+ // Returns the opcode of the target-specific SDNode that implements the 32-bit
191
+ // form of the given Opcode.
192
+ static LoongArchISD::NodeType getLoongArchWOpcode (unsigned Opcode) {
193
+ switch (Opcode) {
194
+ default :
195
+ llvm_unreachable (" Unexpected opcode" );
196
+ case ISD::SHL:
197
+ return LoongArchISD::SLL_W;
198
+ case ISD::SRA:
199
+ return LoongArchISD::SRA_W;
200
+ case ISD::SRL:
201
+ return LoongArchISD::SRL_W;
202
+ }
203
+ }
204
+
205
+ // Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
206
+ // node. Because i8/i16/i32 isn't a legal type for LA64, these operations would
207
+ // otherwise be promoted to i64, making it difficult to select the
208
+ // SLL_W/.../*W later one because the fact the operation was originally of
209
+ // type i8/i16/i32 is lost.
210
+ static SDValue customLegalizeToWOp (SDNode *N, SelectionDAG &DAG,
211
+ unsigned ExtOpc = ISD::ANY_EXTEND) {
212
+ SDLoc DL (N);
213
+ LoongArchISD::NodeType WOpcode = getLoongArchWOpcode (N->getOpcode ());
214
+ SDValue NewOp0 = DAG.getNode (ExtOpc, DL, MVT::i64 , N->getOperand (0 ));
215
+ SDValue NewOp1 = DAG.getNode (ExtOpc, DL, MVT::i64 , N->getOperand (1 ));
216
+ SDValue NewRes = DAG.getNode (WOpcode, DL, MVT::i64 , NewOp0, NewOp1);
217
+ // ReplaceNodeResults requires we maintain the same type for the return value.
218
+ return DAG.getNode (ISD::TRUNCATE, DL, N->getValueType (0 ), NewRes);
219
+ }
220
+
221
+ void LoongArchTargetLowering::ReplaceNodeResults (
222
+ SDNode *N, SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
223
+ SDLoc DL (N);
224
+ switch (N->getOpcode ()) {
225
+ default :
226
+ llvm_unreachable (" Don't know how to legalize this operation" );
227
+ case ISD::SHL:
228
+ case ISD::SRA:
229
+ case ISD::SRL:
230
+ assert (N->getValueType (0 ) == MVT::i32 && Subtarget.is64Bit () &&
231
+ " Unexpected custom legalisation" );
232
+ if (N->getOperand (1 ).getOpcode () != ISD::Constant) {
233
+ Results.push_back (customLegalizeToWOp (N, DAG));
234
+ break ;
235
+ }
236
+ break ;
237
+ }
238
+ }
239
+
53
240
const char *LoongArchTargetLowering::getTargetNodeName (unsigned Opcode) const {
54
241
switch ((LoongArchISD::NodeType)Opcode) {
55
242
case LoongArchISD::FIRST_NUMBER:
@@ -61,6 +248,9 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
61
248
62
249
// TODO: Add more target-dependent nodes later.
63
250
NODE_NAME_CASE (RET)
251
+ NODE_NAME_CASE (SLL_W)
252
+ NODE_NAME_CASE (SRA_W)
253
+ NODE_NAME_CASE (SRL_W)
64
254
}
65
255
#undef NODE_NAME_CASE
66
256
return nullptr ;
0 commit comments