@@ -271,6 +271,22 @@ class ARMDAGToDAGISel : public SelectionDAGISel {
271
271
// Get the alignment operand for a NEON VLD or VST instruction.
272
272
SDValue GetVLDSTAlign (SDValue Align, SDLoc dl, unsigned NumVecs,
273
273
bool is64BitVector);
274
+
275
+ // / Returns the number of instructions required to materialize the given
276
+ // / constant in a register, or 3 if a literal pool load is needed.
277
+ unsigned ConstantMaterializationCost (unsigned Val) const ;
278
+
279
+ // / Checks if N is a multiplication by a constant where we can extract out a
280
+ // / power of two from the constant so that it can be used in a shift, but only
281
+ // / if it simplifies the materialization of the constant. Returns true if it
282
+ // / is, and assigns to PowerOfTwo the power of two that should be extracted
283
+ // / out and to NewMulConst the new constant to be multiplied by.
284
+ bool canExtractShiftFromMul (const SDValue &N, unsigned MaxShift,
285
+ unsigned &PowerOfTwo, SDValue &NewMulConst) const ;
286
+
287
+ // / Replace N with M in CurDAG, in a way that also ensures that M gets
288
+ // / selected when N would have been selected.
289
+ void replaceDAGValue (const SDValue &N, SDValue M);
274
290
};
275
291
}
276
292
@@ -464,13 +480,83 @@ bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
464
480
(ShAmt == 2 || (Subtarget->isSwift () && ShAmt == 1 ));
465
481
}
466
482
483
+ unsigned ARMDAGToDAGISel::ConstantMaterializationCost (unsigned Val) const {
484
+ if (Subtarget->isThumb ()) {
485
+ if (Val <= 255 ) return 1 ; // MOV
486
+ if (Subtarget->hasV6T2Ops () && Val <= 0xffff ) return 1 ; // MOVW
487
+ if (~Val <= 255 ) return 2 ; // MOV + MVN
488
+ if (ARM_AM::isThumbImmShiftedVal (Val)) return 2 ; // MOV + LSL
489
+ } else {
490
+ if (ARM_AM::getSOImmVal (Val) != -1 ) return 1 ; // MOV
491
+ if (ARM_AM::getSOImmVal (~Val) != -1 ) return 1 ; // MVN
492
+ if (Subtarget->hasV6T2Ops () && Val <= 0xffff ) return 1 ; // MOVW
493
+ if (ARM_AM::isSOImmTwoPartVal (Val)) return 2 ; // two instrs
494
+ }
495
+ if (Subtarget->useMovt (*MF)) return 2 ; // MOVW + MOVT
496
+ return 3 ; // Literal pool load
497
+ }
498
+
499
+ bool ARMDAGToDAGISel::canExtractShiftFromMul (const SDValue &N,
500
+ unsigned MaxShift,
501
+ unsigned &PowerOfTwo,
502
+ SDValue &NewMulConst) const {
503
+ assert (N.getOpcode () == ISD::MUL);
504
+ assert (MaxShift > 0 );
505
+
506
+ // If the multiply is used in more than one place then changing the constant
507
+ // will make other uses incorrect, so don't.
508
+ if (!N.hasOneUse ()) return false ;
509
+ // Check if the multiply is by a constant
510
+ ConstantSDNode *MulConst = dyn_cast<ConstantSDNode>(N.getOperand (1 ));
511
+ if (!MulConst) return false ;
512
+ // If the constant is used in more than one place then modifying it will mean
513
+ // we need to materialize two constants instead of one, which is a bad idea.
514
+ if (!MulConst->hasOneUse ()) return false ;
515
+ unsigned MulConstVal = MulConst->getZExtValue ();
516
+ if (MulConstVal == 0 ) return false ;
517
+
518
+ // Find the largest power of 2 that MulConstVal is a multiple of
519
+ PowerOfTwo = MaxShift;
520
+ while ((MulConstVal % (1 << PowerOfTwo)) != 0 ) {
521
+ --PowerOfTwo;
522
+ if (PowerOfTwo == 0 ) return false ;
523
+ }
524
+
525
+ // Only optimise if the new cost is better
526
+ unsigned NewMulConstVal = MulConstVal / (1 << PowerOfTwo);
527
+ NewMulConst = CurDAG->getConstant (NewMulConstVal, SDLoc (N), MVT::i32 );
528
+ unsigned OldCost = ConstantMaterializationCost (MulConstVal);
529
+ unsigned NewCost = ConstantMaterializationCost (NewMulConstVal);
530
+ return NewCost < OldCost;
531
+ }
532
+
533
+ void ARMDAGToDAGISel::replaceDAGValue (const SDValue &N, SDValue M) {
534
+ CurDAG->RepositionNode (N.getNode (), M.getNode ());
535
+ CurDAG->ReplaceAllUsesWith (N, M);
536
+ }
537
+
467
538
bool ARMDAGToDAGISel::SelectImmShifterOperand (SDValue N,
468
539
SDValue &BaseReg,
469
540
SDValue &Opc,
470
541
bool CheckProfitability) {
471
542
if (DisableShifterOp)
472
543
return false ;
473
544
545
+ // If N is a multiply-by-constant and it's profitable to extract a shift and
546
+ // use it in a shifted operand do so.
547
+ if (N.getOpcode () == ISD::MUL) {
548
+ unsigned PowerOfTwo = 0 ;
549
+ SDValue NewMulConst;
550
+ if (canExtractShiftFromMul (N, 31 , PowerOfTwo, NewMulConst)) {
551
+ replaceDAGValue (N.getOperand (1 ), NewMulConst);
552
+ BaseReg = N;
553
+ Opc = CurDAG->getTargetConstant (ARM_AM::getSORegOpc (ARM_AM::lsl,
554
+ PowerOfTwo),
555
+ SDLoc (N), MVT::i32 );
556
+ return true ;
557
+ }
558
+ }
559
+
474
560
ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode (N.getOpcode ());
475
561
476
562
// Don't match base register only case. That is matched to a separate
@@ -655,6 +741,18 @@ bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset,
655
741
}
656
742
}
657
743
744
+ // If Offset is a multiply-by-constant and it's profitable to extract a shift
745
+ // and use it in a shifted operand do so.
746
+ if (Offset.getOpcode () == ISD::MUL) {
747
+ unsigned PowerOfTwo = 0 ;
748
+ SDValue NewMulConst;
749
+ if (canExtractShiftFromMul (Offset, 31 , PowerOfTwo, NewMulConst)) {
750
+ replaceDAGValue (Offset.getOperand (1 ), NewMulConst);
751
+ ShAmt = PowerOfTwo;
752
+ ShOpcVal = ARM_AM::lsl;
753
+ }
754
+ }
755
+
658
756
Opc = CurDAG->getTargetConstant (ARM_AM::getAM2Opc (AddSub, ShAmt, ShOpcVal),
659
757
SDLoc (N), MVT::i32 );
660
758
return true ;
@@ -1314,6 +1412,17 @@ bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
1314
1412
}
1315
1413
}
1316
1414
1415
+ // If OffReg is a multiply-by-constant and it's profitable to extract a shift
1416
+ // and use it in a shifted operand do so.
1417
+ if (OffReg.getOpcode () == ISD::MUL) {
1418
+ unsigned PowerOfTwo = 0 ;
1419
+ SDValue NewMulConst;
1420
+ if (canExtractShiftFromMul (OffReg, 3 , PowerOfTwo, NewMulConst)) {
1421
+ replaceDAGValue (OffReg.getOperand (1 ), NewMulConst);
1422
+ ShAmt = PowerOfTwo;
1423
+ }
1424
+ }
1425
+
1317
1426
ShImm = CurDAG->getTargetConstant (ShAmt, SDLoc (N), MVT::i32 );
1318
1427
1319
1428
return true ;
@@ -2392,25 +2501,8 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
2392
2501
}
2393
2502
case ISD::Constant: {
2394
2503
unsigned Val = cast<ConstantSDNode>(N)->getZExtValue ();
2395
- bool UseCP = true ;
2396
- if (Subtarget->useMovt (*MF))
2397
- // Thumb2-aware targets have the MOVT instruction, so all immediates can
2398
- // be done with MOV + MOVT, at worst.
2399
- UseCP = false ;
2400
- else {
2401
- if (Subtarget->isThumb ()) {
2402
- UseCP = (Val > 255 && // MOV
2403
- ~Val > 255 && // MOV + MVN
2404
- !ARM_AM::isThumbImmShiftedVal (Val) && // MOV + LSL
2405
- !(Subtarget->hasV6T2Ops () && Val <= 0xffff )); // MOVW
2406
- } else
2407
- UseCP = (ARM_AM::getSOImmVal (Val) == -1 && // MOV
2408
- ARM_AM::getSOImmVal (~Val) == -1 && // MVN
2409
- !ARM_AM::isSOImmTwoPartVal (Val) && // two instrs.
2410
- !(Subtarget->hasV6T2Ops () && Val <= 0xffff )); // MOVW
2411
- }
2412
-
2413
- if (UseCP) {
2504
+ // If we can't materialize the constant we need to use a literal pool
2505
+ if (ConstantMaterializationCost (Val) > 2 ) {
2414
2506
SDValue CPIdx = CurDAG->getTargetConstantPool (
2415
2507
ConstantInt::get (Type::getInt32Ty (*CurDAG->getContext ()), Val),
2416
2508
TLI->getPointerTy (CurDAG->getDataLayout ()));
0 commit comments