@@ -42,6 +42,12 @@ class CSKYDAGToDAGISel : public SelectionDAGISel {
42
42
void Select (SDNode *N) override ;
43
43
bool selectAddCarry (SDNode *N);
44
44
bool selectSubCarry (SDNode *N);
45
+ bool selectInlineAsm (SDNode *N);
46
+
47
+ SDNode *createGPRPairNode (EVT VT, SDValue V0, SDValue V1);
48
+
49
+ bool SelectInlineAsmMemoryOperand (const SDValue &Op, unsigned ConstraintID,
50
+ std::vector<SDValue> &OutOps) override ;
45
51
46
52
#include " CSKYGenDAGISel.inc"
47
53
};
@@ -86,6 +92,10 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
86
92
IsSelected = true ;
87
93
break ;
88
94
}
95
+ case ISD::INLINEASM:
96
+ case ISD::INLINEASM_BR:
97
+ IsSelected = selectInlineAsm (N);
98
+ break ;
89
99
}
90
100
91
101
if (IsSelected)
@@ -95,6 +105,167 @@ void CSKYDAGToDAGISel::Select(SDNode *N) {
95
105
SelectCode (N);
96
106
}
97
107
108
+ bool CSKYDAGToDAGISel::selectInlineAsm (SDNode *N) {
109
+ std::vector<SDValue> AsmNodeOperands;
110
+ unsigned Flag, Kind;
111
+ bool Changed = false ;
112
+ unsigned NumOps = N->getNumOperands ();
113
+
114
+ // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
115
+ // However, some instructions (e.g. mula.s32) require GPR pair.
116
+ // Since there is no constraint to explicitly specify a
117
+ // reg pair, we use GPRPair reg class for "%r" for 64-bit data.
118
+
119
+ SDLoc dl (N);
120
+ SDValue Glue =
121
+ N->getGluedNode () ? N->getOperand (NumOps - 1 ) : SDValue (nullptr , 0 );
122
+
123
+ SmallVector<bool , 8 > OpChanged;
124
+ // Glue node will be appended late.
125
+ for (unsigned i = 0 , e = N->getGluedNode () ? NumOps - 1 : NumOps; i < e;
126
+ ++i) {
127
+ SDValue op = N->getOperand (i);
128
+ AsmNodeOperands.push_back (op);
129
+
130
+ if (i < InlineAsm::Op_FirstOperand)
131
+ continue ;
132
+
133
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand (i))) {
134
+ Flag = C->getZExtValue ();
135
+ Kind = InlineAsm::getKind (Flag);
136
+ } else
137
+ continue ;
138
+
139
+ // Immediate operands to inline asm in the SelectionDAG are modeled with
140
+ // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
141
+ // the second is a constant with the value of the immediate. If we get here
142
+ // and we have a Kind_Imm, skip the next operand, and continue.
143
+ if (Kind == InlineAsm::Kind_Imm) {
144
+ SDValue op = N->getOperand (++i);
145
+ AsmNodeOperands.push_back (op);
146
+ continue ;
147
+ }
148
+
149
+ unsigned NumRegs = InlineAsm::getNumOperandRegisters (Flag);
150
+ if (NumRegs)
151
+ OpChanged.push_back (false );
152
+
153
+ unsigned DefIdx = 0 ;
154
+ bool IsTiedToChangedOp = false ;
155
+ // If it's a use that is tied with a previous def, it has no
156
+ // reg class constraint.
157
+ if (Changed && InlineAsm::isUseOperandTiedToDef (Flag, DefIdx))
158
+ IsTiedToChangedOp = OpChanged[DefIdx];
159
+
160
+ // Memory operands to inline asm in the SelectionDAG are modeled with two
161
+ // operands: a constant of value InlineAsm::Kind_Mem followed by the input
162
+ // operand. If we get here and we have a Kind_Mem, skip the next operand (so
163
+ // it doesn't get misinterpreted), and continue. We do this here because
164
+ // it's important to update the OpChanged array correctly before moving on.
165
+ if (Kind == InlineAsm::Kind_Mem) {
166
+ SDValue op = N->getOperand (++i);
167
+ AsmNodeOperands.push_back (op);
168
+ continue ;
169
+ }
170
+
171
+ if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef &&
172
+ Kind != InlineAsm::Kind_RegDefEarlyClobber)
173
+ continue ;
174
+
175
+ unsigned RC;
176
+ bool HasRC = InlineAsm::hasRegClassConstraint (Flag, RC);
177
+ if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
178
+ NumRegs != 2 )
179
+ continue ;
180
+
181
+ assert ((i + 2 < NumOps) && " Invalid number of operands in inline asm" );
182
+ SDValue V0 = N->getOperand (i + 1 );
183
+ SDValue V1 = N->getOperand (i + 2 );
184
+ unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg ();
185
+ unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg ();
186
+ SDValue PairedReg;
187
+ MachineRegisterInfo &MRI = MF->getRegInfo ();
188
+
189
+ if (Kind == InlineAsm::Kind_RegDef ||
190
+ Kind == InlineAsm::Kind_RegDefEarlyClobber) {
191
+ // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
192
+ // the original GPRs.
193
+
194
+ Register GPVR = MRI.createVirtualRegister (&CSKY::GPRPairRegClass);
195
+ PairedReg = CurDAG->getRegister (GPVR, MVT::i64 );
196
+ SDValue Chain = SDValue (N, 0 );
197
+
198
+ SDNode *GU = N->getGluedUser ();
199
+ SDValue RegCopy =
200
+ CurDAG->getCopyFromReg (Chain, dl, GPVR, MVT::i64 , Chain.getValue (1 ));
201
+
202
+ // Extract values from a GPRPair reg and copy to the original GPR reg.
203
+ SDValue Sub0 =
204
+ CurDAG->getTargetExtractSubreg (CSKY::sub32_0, dl, MVT::i32 , RegCopy);
205
+ SDValue Sub1 =
206
+ CurDAG->getTargetExtractSubreg (CSKY::sub32_32, dl, MVT::i32 , RegCopy);
207
+ SDValue T0 =
208
+ CurDAG->getCopyToReg (Sub0, dl, Reg0, Sub0, RegCopy.getValue (1 ));
209
+ SDValue T1 = CurDAG->getCopyToReg (Sub1, dl, Reg1, Sub1, T0.getValue (1 ));
210
+
211
+ // Update the original glue user.
212
+ std::vector<SDValue> Ops (GU->op_begin (), GU->op_end () - 1 );
213
+ Ops.push_back (T1.getValue (1 ));
214
+ CurDAG->UpdateNodeOperands (GU, Ops);
215
+ } else {
216
+ // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
217
+ // GPRPair and then pass the GPRPair to the inline asm.
218
+ SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
219
+
220
+ // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
221
+ SDValue T0 =
222
+ CurDAG->getCopyFromReg (Chain, dl, Reg0, MVT::i32 , Chain.getValue (1 ));
223
+ SDValue T1 =
224
+ CurDAG->getCopyFromReg (Chain, dl, Reg1, MVT::i32 , T0.getValue (1 ));
225
+ SDValue Pair = SDValue (createGPRPairNode (MVT::i64 , T0, T1), 0 );
226
+
227
+ // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
228
+ // i32 VRs of inline asm with it.
229
+ Register GPVR = MRI.createVirtualRegister (&CSKY::GPRPairRegClass);
230
+ PairedReg = CurDAG->getRegister (GPVR, MVT::i64 );
231
+ Chain = CurDAG->getCopyToReg (T1, dl, GPVR, Pair, T1.getValue (1 ));
232
+
233
+ AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
234
+ Glue = Chain.getValue (1 );
235
+ }
236
+
237
+ Changed = true ;
238
+
239
+ if (PairedReg.getNode ()) {
240
+ OpChanged[OpChanged.size () - 1 ] = true ;
241
+ Flag = InlineAsm::getFlagWord (Kind, 1 /* RegNum*/ );
242
+ if (IsTiedToChangedOp)
243
+ Flag = InlineAsm::getFlagWordForMatchingOp (Flag, DefIdx);
244
+ else
245
+ Flag = InlineAsm::getFlagWordForRegClass (Flag, CSKY::GPRPairRegClassID);
246
+ // Replace the current flag.
247
+ AsmNodeOperands[AsmNodeOperands.size () - 1 ] =
248
+ CurDAG->getTargetConstant (Flag, dl, MVT::i32 );
249
+ // Add the new register node and skip the original two GPRs.
250
+ AsmNodeOperands.push_back (PairedReg);
251
+ // Skip the next two GPRs.
252
+ i += 2 ;
253
+ }
254
+ }
255
+
256
+ if (Glue.getNode ())
257
+ AsmNodeOperands.push_back (Glue);
258
+ if (!Changed)
259
+ return false ;
260
+
261
+ SDValue New = CurDAG->getNode (N->getOpcode (), SDLoc (N),
262
+ CurDAG->getVTList (MVT::Other, MVT::Glue),
263
+ AsmNodeOperands);
264
+ New->setNodeId (-1 );
265
+ ReplaceNode (N, New.getNode ());
266
+ return true ;
267
+ }
268
+
98
269
bool CSKYDAGToDAGISel::selectAddCarry (SDNode *N) {
99
270
MachineSDNode *NewNode = nullptr ;
100
271
auto Type0 = N->getValueType (0 );
@@ -175,6 +346,31 @@ bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
175
346
return true ;
176
347
}
177
348
349
+ SDNode *CSKYDAGToDAGISel::createGPRPairNode (EVT VT, SDValue V0, SDValue V1) {
350
+ SDLoc dl (V0.getNode ());
351
+ SDValue RegClass =
352
+ CurDAG->getTargetConstant (CSKY::GPRPairRegClassID, dl, MVT::i32 );
353
+ SDValue SubReg0 = CurDAG->getTargetConstant (CSKY::sub32_0, dl, MVT::i32 );
354
+ SDValue SubReg1 = CurDAG->getTargetConstant (CSKY::sub32_32, dl, MVT::i32 );
355
+ const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};
356
+ return CurDAG->getMachineNode (TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
357
+ }
358
+
359
+ bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand (
360
+ const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) {
361
+ switch (ConstraintID) {
362
+ case InlineAsm::Constraint_m:
363
+ // We just support simple memory operands that have a single address
364
+ // operand and need no special handling.
365
+ OutOps.push_back (Op);
366
+ return false ;
367
+ default :
368
+ break ;
369
+ }
370
+
371
+ return true ;
372
+ }
373
+
178
374
FunctionPass *llvm::createCSKYISelDag (CSKYTargetMachine &TM) {
179
375
return new CSKYDAGToDAGISel (TM);
180
376
}
0 commit comments