@@ -107,6 +107,8 @@ class X86FastISel : public FastISel {
107
107
108
108
bool X86SelectShift (const Instruction *I);
109
109
110
+ bool X86SelectDivRem (const Instruction *I);
111
+
110
112
bool X86SelectSelect (const Instruction *I);
111
113
112
114
bool X86SelectTrunc (const Instruction *I);
@@ -1235,6 +1237,124 @@ bool X86FastISel::X86SelectShift(const Instruction *I) {
1235
1237
return true ;
1236
1238
}
1237
1239
1240
+ bool X86FastISel::X86SelectDivRem (const Instruction *I) {
1241
+ const static unsigned NumTypes = 4 ; // i8, i16, i32, i64
1242
+ const static unsigned NumOps = 4 ; // SDiv, SRem, UDiv, URem
1243
+ const static bool S = true ; // IsSigned
1244
+ const static bool U = false ; // !IsSigned
1245
+ const static unsigned Copy = TargetOpcode::COPY;
1246
+ // For the X86 DIV/IDIV instruction, in most cases the dividend
1247
+ // (numerator) must be in a specific register pair highreg:lowreg,
1248
+ // producing the quotient in lowreg and the remainder in highreg.
1249
+ // For most data types, to set up the instruction, the dividend is
1250
+ // copied into lowreg, and lowreg is sign-extended or zero-extended
1251
+ // into highreg. The exception is i8, where the dividend is defined
1252
+ // as a single register rather than a register pair, and we
1253
+ // therefore directly sign-extend or zero-extend the dividend into
1254
+ // lowreg, instead of copying, and ignore the highreg.
1255
+ const static struct DivRemEntry {
1256
+ // The following portion depends only on the data type.
1257
+ const TargetRegisterClass *RC;
1258
+ unsigned LowInReg; // low part of the register pair
1259
+ unsigned HighInReg; // high part of the register pair
1260
+ // The following portion depends on both the data type and the operation.
1261
+ struct DivRemResult {
1262
+ unsigned OpDivRem; // The specific DIV/IDIV opcode to use.
1263
+ unsigned OpSignExtend; // Opcode for sign-extending lowreg into
1264
+ // highreg, or copying a zero into highreg.
1265
+ unsigned OpCopy; // Opcode for copying dividend into lowreg, or
1266
+ // zero/sign-extending into lowreg for i8.
1267
+ unsigned DivRemResultReg; // Register containing the desired result.
1268
+ bool IsOpSigned; // Whether to use signed or unsigned form.
1269
+ } ResultTable[NumOps];
1270
+ } OpTable[NumTypes] = {
1271
+ { &X86::GR8RegClass, X86::AX, 0 , {
1272
+ { X86::IDIV8r, 0 , X86::MOVSX16rr8, X86::AL, S }, // SDiv
1273
+ { X86::IDIV8r, 0 , X86::MOVSX16rr8, X86::AH, S }, // SRem
1274
+ { X86::DIV8r, 0 , X86::MOVZX16rr8, X86::AL, U }, // UDiv
1275
+ { X86::DIV8r, 0 , X86::MOVZX16rr8, X86::AH, U }, // URem
1276
+ }
1277
+ }, // i8
1278
+ { &X86::GR16RegClass, X86::AX, X86::DX, {
1279
+ { X86::IDIV16r, X86::CWD, Copy, X86::AX, S }, // SDiv
1280
+ { X86::IDIV16r, X86::CWD, Copy, X86::DX, S }, // SRem
1281
+ { X86::DIV16r, X86::MOV16r0, Copy, X86::AX, U }, // UDiv
1282
+ { X86::DIV16r, X86::MOV16r0, Copy, X86::DX, U }, // URem
1283
+ }
1284
+ }, // i16
1285
+ { &X86::GR32RegClass, X86::EAX, X86::EDX, {
1286
+ { X86::IDIV32r, X86::CDQ, Copy, X86::EAX, S }, // SDiv
1287
+ { X86::IDIV32r, X86::CDQ, Copy, X86::EDX, S }, // SRem
1288
+ { X86::DIV32r, X86::MOV32r0, Copy, X86::EAX, U }, // UDiv
1289
+ { X86::DIV32r, X86::MOV32r0, Copy, X86::EDX, U }, // URem
1290
+ }
1291
+ }, // i32
1292
+ { &X86::GR64RegClass, X86::RAX, X86::RDX, {
1293
+ { X86::IDIV64r, X86::CQO, Copy, X86::RAX, S }, // SDiv
1294
+ { X86::IDIV64r, X86::CQO, Copy, X86::RDX, S }, // SRem
1295
+ { X86::DIV64r, X86::MOV64r0, Copy, X86::RAX, U }, // UDiv
1296
+ { X86::DIV64r, X86::MOV64r0, Copy, X86::RDX, U }, // URem
1297
+ }
1298
+ }, // i64
1299
+ };
1300
+
1301
+ MVT VT;
1302
+ if (!isTypeLegal (I->getType (), VT))
1303
+ return false ;
1304
+
1305
+ unsigned TypeIndex, OpIndex;
1306
+ switch (VT.SimpleTy ) {
1307
+ default : return false ;
1308
+ case MVT::i8: TypeIndex = 0 ; break ;
1309
+ case MVT::i16: TypeIndex = 1 ; break ;
1310
+ case MVT::i32: TypeIndex = 2 ; break ;
1311
+ case MVT::i64: TypeIndex = 3 ;
1312
+ if (!Subtarget->is64Bit ())
1313
+ return false ;
1314
+ break ;
1315
+ }
1316
+
1317
+ switch (I->getOpcode ()) {
1318
+ default : llvm_unreachable (" Unexpected div/rem opcode" );
1319
+ case Instruction::SDiv: OpIndex = 0 ; break ;
1320
+ case Instruction::SRem: OpIndex = 1 ; break ;
1321
+ case Instruction::UDiv: OpIndex = 2 ; break ;
1322
+ case Instruction::URem: OpIndex = 3 ; break ;
1323
+ }
1324
+
1325
+ const DivRemEntry &TypeEntry = OpTable[TypeIndex];
1326
+ const DivRemEntry::DivRemResult &OpEntry = TypeEntry.ResultTable [OpIndex];
1327
+ unsigned Op0Reg = getRegForValue (I->getOperand (0 ));
1328
+ if (Op0Reg == 0 )
1329
+ return false ;
1330
+ unsigned Op1Reg = getRegForValue (I->getOperand (1 ));
1331
+ if (Op1Reg == 0 )
1332
+ return false ;
1333
+
1334
+ // Move op0 into low-order input register.
1335
+ BuildMI (*FuncInfo.MBB , FuncInfo.InsertPt , DL,
1336
+ TII.get (OpEntry.OpCopy ), TypeEntry.LowInReg ).addReg (Op0Reg);
1337
+ // Zero-extend or sign-extend into high-order input register.
1338
+ if (OpEntry.OpSignExtend ) {
1339
+ if (OpEntry.IsOpSigned )
1340
+ BuildMI (*FuncInfo.MBB , FuncInfo.InsertPt , DL,
1341
+ TII.get (OpEntry.OpSignExtend ));
1342
+ else
1343
+ BuildMI (*FuncInfo.MBB , FuncInfo.InsertPt , DL,
1344
+ TII.get (OpEntry.OpSignExtend ), TypeEntry.HighInReg );
1345
+ }
1346
+ // Generate the DIV/IDIV instruction.
1347
+ BuildMI (*FuncInfo.MBB , FuncInfo.InsertPt , DL,
1348
+ TII.get (OpEntry.OpDivRem )).addReg (Op1Reg);
1349
+ // Copy output register into result register.
1350
+ unsigned ResultReg = createResultReg (TypeEntry.RC );
1351
+ BuildMI (*FuncInfo.MBB , FuncInfo.InsertPt , DL,
1352
+ TII.get (Copy), ResultReg).addReg (OpEntry.DivRemResultReg );
1353
+ UpdateValueMap (I, ResultReg);
1354
+
1355
+ return true ;
1356
+ }
1357
+
1238
1358
bool X86FastISel::X86SelectSelect (const Instruction *I) {
1239
1359
MVT VT;
1240
1360
if (!isTypeLegal (I->getType (), VT))
@@ -2084,6 +2204,11 @@ X86FastISel::TargetSelectInstruction(const Instruction *I) {
2084
2204
case Instruction::AShr:
2085
2205
case Instruction::Shl:
2086
2206
return X86SelectShift (I);
2207
+ case Instruction::SDiv:
2208
+ case Instruction::UDiv:
2209
+ case Instruction::SRem:
2210
+ case Instruction::URem:
2211
+ return X86SelectDivRem (I);
2087
2212
case Instruction::Select:
2088
2213
return X86SelectSelect (I);
2089
2214
case Instruction::Trunc:
0 commit comments