Skip to content

Commit

Permalink
[AArch64] Improve code generation for logical instructions taking
Browse files Browse the repository at this point in the history
immediate operands.

This commit adds an AArch64 dag-combine that optimizes code generation
for logical instructions taking immediate operands. The optimization
uses demanded bits to change a logical instruction's immediate operand
so that the immediate can be folded into the immediate field of the
instruction.

rdar://problem/18231627

Differential Revision: https://reviews.llvm.org/D5591

llvm-svn: 300913
  • Loading branch information
ahatanaka committed Apr 20, 2017
1 parent cc663b8 commit e327f09
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 58 deletions.
53 changes: 31 additions & 22 deletions llvm/include/llvm/Target/TargetLowering.h
Expand Up @@ -2388,30 +2388,39 @@ class TargetLowering : public TargetLoweringBase {
New = N;
return true;
}

/// Check to see if the specified operand of the specified instruction is a
/// constant integer. If so, check to see if there are any bits set in the
/// constant that are not demanded. If so, shrink the constant and return
/// true.
bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded);

/// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This
/// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be
/// generalized for targets with other types of implicit widening casts.
bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded,
const SDLoc &dl);

/// Helper for SimplifyDemandedBits that can simplify an operation with
/// multiple uses. This function uses TLI.SimplifyDemandedBits to
/// simplify Operand \p OpIdx of \p User and then updated \p User with
/// the simplified version. No other uses of \p OpIdx are updated.
/// If \p User is the only user of \p OpIdx, this function behaves exactly
/// like TLI.SimplifyDemandedBits except that it also updates the DAG by
/// calling DCI.CommitTargetLoweringOpt.
bool SimplifyDemandedBits(SDNode *User, unsigned OpIdx,
const APInt &Demanded, DAGCombinerInfo &DCI);
};

/// Check to see if the specified operand of the specified instruction is a
/// constant integer. If so, check to see if there are any bits set in the
/// constant that are not demanded. If so, shrink the constant and return
/// true.
bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded,
TargetLoweringOpt &TLO) const;

// Target hook to do target-specific const optimization, which is called by
// ShrinkDemandedConstant. This function should return true if the target
// doesn't want ShrinkDemandedConstant to further optimize the constant.
virtual bool targetShrinkDemandedConstant(SDValue Op, const APInt &Demanded,
TargetLoweringOpt &TLO) const {
return false;
}

/// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This
/// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be
/// generalized for targets with other types of implicit widening casts.
bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded,
TargetLoweringOpt &TLO) const;

/// Helper for SimplifyDemandedBits that can simplify an operation with
/// multiple uses. This function simplifies operand \p OpIdx of \p User and
/// then updates \p User with the simplified version. No other uses of
/// \p OpIdx are updated. If \p User is the only user of \p OpIdx, this
/// function behaves exactly like function SimplifyDemandedBits declared
/// below except that it also updates the DAG by calling
/// DCI.CommitTargetLoweringOpt.
bool SimplifyDemandedBits(SDNode *User, unsigned OpIdx, const APInt &Demanded,
DAGCombinerInfo &DCI, TargetLoweringOpt &TLO) const;

/// Look at Op. At this point, we know that only the DemandedMask bits of the
/// result of Op are ever used downstream. If we can use this information to
/// simplify Op, create a new simplified DAG node and return true, returning
Expand Down
66 changes: 36 additions & 30 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Expand Up @@ -342,11 +342,16 @@ TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
/// If the specified instruction has a constant integer operand and there are
/// bits set in that constant that are not demanded, then clear those bits and
/// return true.
bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(
SDValue Op, const APInt &Demanded) {
bool TargetLowering::ShrinkDemandedConstant(SDValue Op, const APInt &Demanded,
TargetLoweringOpt &TLO) const {
SelectionDAG &DAG = TLO.DAG;
SDLoc DL(Op);
unsigned Opcode = Op.getOpcode();

// Do target-specific constant optimization.
if (targetShrinkDemandedConstant(Op, Demanded, TLO))
return TLO.New.getNode();

// FIXME: ISD::SELECT, ISD::SELECT_CC
switch (Opcode) {
default:
Expand All @@ -367,7 +372,7 @@ bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(
EVT VT = Op.getValueType();
SDValue NewC = DAG.getConstant(Demanded & C, DL, VT);
SDValue NewOp = DAG.getNode(Opcode, DL, VT, Op.getOperand(0), NewC);
return CombineTo(Op, NewOp);
return TLO.CombineTo(Op, NewOp);
}

break;
Expand All @@ -380,15 +385,17 @@ bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(
/// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free.
/// This uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be
/// generalized for targets with other types of implicit widening casts.
bool TargetLowering::TargetLoweringOpt::ShrinkDemandedOp(SDValue Op,
unsigned BitWidth,
const APInt &Demanded,
const SDLoc &dl) {
bool TargetLowering::ShrinkDemandedOp(SDValue Op, unsigned BitWidth,
const APInt &Demanded,
TargetLoweringOpt &TLO) const {
assert(Op.getNumOperands() == 2 &&
"ShrinkDemandedOp only supports binary operators!");
assert(Op.getNode()->getNumValues() == 1 &&
"ShrinkDemandedOp only supports nodes with one result!");

SelectionDAG &DAG = TLO.DAG;
SDLoc dl(Op);

// Early return, as this function cannot handle vector types.
if (Op.getValueType().isVector())
return false;
Expand Down Expand Up @@ -418,23 +425,22 @@ bool TargetLowering::TargetLoweringOpt::ShrinkDemandedOp(SDValue Op,
bool NeedZext = DemandedSize > SmallVTBits;
SDValue Z = DAG.getNode(NeedZext ? ISD::ZERO_EXTEND : ISD::ANY_EXTEND,
dl, Op.getValueType(), X);
return CombineTo(Op, Z);
return TLO.CombineTo(Op, Z);
}
}
return false;
}

bool
TargetLowering::TargetLoweringOpt::SimplifyDemandedBits(SDNode *User,
unsigned OpIdx,
const APInt &Demanded,
DAGCombinerInfo &DCI) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
TargetLowering::SimplifyDemandedBits(SDNode *User, unsigned OpIdx,
const APInt &Demanded,
DAGCombinerInfo &DCI,
TargetLoweringOpt &TLO) const {
SDValue Op = User->getOperand(OpIdx);
APInt KnownZero, KnownOne;

if (!TLI.SimplifyDemandedBits(Op, Demanded, KnownZero, KnownOne,
*this, 0, true))
if (!SimplifyDemandedBits(Op, Demanded, KnownZero, KnownOne,
TLO, 0, true))
return false;


Expand All @@ -446,27 +452,27 @@ TargetLowering::TargetLoweringOpt::SimplifyDemandedBits(SDNode *User,
// with the value 'x', which will give us:
// Old = i32 and x, 0xffffff
// New = x
if (Old.hasOneUse()) {
if (TLO.Old.hasOneUse()) {
// For the one use case, we just commit the change.
DCI.CommitTargetLoweringOpt(*this);
DCI.CommitTargetLoweringOpt(TLO);
return true;
}

// If Old has more than one use then it must be Op, because the
// AssumeSingleUse flag is not propogated to recursive calls of
// SimplifyDemanded bits, so the only node with multiple use that
// it will attempt to combine will be opt.
assert(Old == Op);
assert(TLO.Old == Op);

SmallVector <SDValue, 4> NewOps;
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) {
if (i == OpIdx) {
NewOps.push_back(New);
NewOps.push_back(TLO.New);
continue;
}
NewOps.push_back(User->getOperand(i));
}
DAG.UpdateNodeOperands(User, NewOps);
TLO.DAG.UpdateNodeOperands(User, NewOps);
// Op has less users now, so we may be able to perform additional combines
// with it.
DCI.AddToWorklist(Op.getNode());
Expand Down Expand Up @@ -585,7 +591,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,

// If any of the set bits in the RHS are known zero on the LHS, shrink
// the constant.
if (TLO.ShrinkDemandedConstant(Op, ~LHSZero & NewMask))
if (ShrinkDemandedConstant(Op, ~LHSZero & NewMask, TLO))
return true;

// Bitwise-not (xor X, -1) is a special case: we don't usually shrink its
Expand Down Expand Up @@ -620,10 +626,10 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
if ((NewMask & (KnownZero|KnownZero2)) == NewMask)
return TLO.CombineTo(Op, TLO.DAG.getConstant(0, dl, Op.getValueType()));
// If the RHS is a constant, see if we can simplify it.
if (TLO.ShrinkDemandedConstant(Op, ~KnownZero2 & NewMask))
if (ShrinkDemandedConstant(Op, ~KnownZero2 & NewMask, TLO))
return true;
// If the operation can be done in a smaller type, do so.
if (TLO.ShrinkDemandedOp(Op, BitWidth, NewMask, dl))
if (ShrinkDemandedOp(Op, BitWidth, NewMask, TLO))
return true;

// Output known-1 bits are only known if set in both the LHS & RHS.
Expand Down Expand Up @@ -654,10 +660,10 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
if ((NewMask & ~KnownZero2 & KnownOne) == (~KnownZero2 & NewMask))
return TLO.CombineTo(Op, Op.getOperand(1));
// If the RHS is a constant, see if we can simplify it.
if (TLO.ShrinkDemandedConstant(Op, NewMask))
if (ShrinkDemandedConstant(Op, NewMask, TLO))
return true;
// If the operation can be done in a smaller type, do so.
if (TLO.ShrinkDemandedOp(Op, BitWidth, NewMask, dl))
if (ShrinkDemandedOp(Op, BitWidth, NewMask, TLO))
return true;

// Output known-0 bits are only known if clear in both the LHS & RHS.
Expand All @@ -682,7 +688,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
if ((KnownZero2 & NewMask) == NewMask)
return TLO.CombineTo(Op, Op.getOperand(1));
// If the operation can be done in a smaller type, do so.
if (TLO.ShrinkDemandedOp(Op, BitWidth, NewMask, dl))
if (ShrinkDemandedOp(Op, BitWidth, NewMask, TLO))
return true;

// If all of the unknown bits are known to be zero on one side or the other
Expand Down Expand Up @@ -727,7 +733,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
}
// If it already has all the bits set, nothing to change
// but don't shrink either!
} else if (TLO.ShrinkDemandedConstant(Op, NewMask)) {
} else if (ShrinkDemandedConstant(Op, NewMask, TLO)) {
return true;
}
}
Expand All @@ -746,7 +752,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");

// If the operands are constants, see if we can simplify them.
if (TLO.ShrinkDemandedConstant(Op, NewMask))
if (ShrinkDemandedConstant(Op, NewMask, TLO))
return true;

// Only known if known in both the LHS and RHS.
Expand All @@ -764,7 +770,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?");

// If the operands are constants, see if we can simplify them.
if (TLO.ShrinkDemandedConstant(Op, NewMask))
if (ShrinkDemandedConstant(Op, NewMask, TLO))
return true;

// Only known if known in both the LHS and RHS.
Expand Down Expand Up @@ -1284,7 +1290,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op,
SimplifyDemandedBits(Op.getOperand(1), LoMask, KnownZero2,
KnownOne2, TLO, Depth+1) ||
// See if the operation should be performed at a smaller bit width.
TLO.ShrinkDemandedOp(Op, BitWidth, NewMask, dl)) {
ShrinkDemandedOp(Op, BitWidth, NewMask, TLO)) {
const SDNodeFlags *Flags = Op.getNode()->getFlags();
if (Flags->hasNoSignedWrap() || Flags->hasNoUnsignedWrap()) {
// Disable the nsw and nuw flags. We can no longer guarantee that we
Expand Down

0 comments on commit e327f09

Please sign in to comment.