Skip to content
This repository was archived by the owner on Sep 2, 2018. It is now read-only.

Commit e50e6f3

Browse files
[ARM] Extract shifts out of multiply-by-constant
Turning (op x (mul y k)) into (op x (lsl (mul y k>>n) n)) is beneficial when we can do the lsl as a shifted operand and the resulting multiply constant is simpler to generate. Do this by doing the transformation when trying to select a shifted operand, as that ensures that it actually turns out better (the alternative would be to do it in PreprocessISelDAG, but we don't know for sure there if extracting the shift would allow a shifted operand to be used). Differential Revision: http://reviews.llvm.org/D12196 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247569 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 74e437e commit e50e6f3

File tree

2 files changed

+293
-50
lines changed

2 files changed

+293
-50
lines changed

lib/Target/ARM/ARMISelDAGToDAG.cpp

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ class ARMDAGToDAGISel : public SelectionDAGISel {
271271
// Get the alignment operand for a NEON VLD or VST instruction.
272272
SDValue GetVLDSTAlign(SDValue Align, SDLoc dl, unsigned NumVecs,
273273
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);
274290
};
275291
}
276292

@@ -464,13 +480,83 @@ bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
464480
(ShAmt == 2 || (Subtarget->isSwift() && ShAmt == 1));
465481
}
466482

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+
467538
bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
468539
SDValue &BaseReg,
469540
SDValue &Opc,
470541
bool CheckProfitability) {
471542
if (DisableShifterOp)
472543
return false;
473544

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+
474560
ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
475561

476562
// 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,
655741
}
656742
}
657743

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+
658756
Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
659757
SDLoc(N), MVT::i32);
660758
return true;
@@ -1314,6 +1412,17 @@ bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
13141412
}
13151413
}
13161414

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+
13171426
ShImm = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32);
13181427

13191428
return true;
@@ -2392,25 +2501,8 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
23922501
}
23932502
case ISD::Constant: {
23942503
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) {
24142506
SDValue CPIdx = CurDAG->getTargetConstantPool(
24152507
ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
24162508
TLI->getPointerTy(CurDAG->getDataLayout()));

0 commit comments

Comments
 (0)