Skip to content

Commit 6621234

Browse files
committed
[InstCombine] Avoid DeMorgan's on occasion
When `andn` is available, we should avoid switching `s &= ~(z & ~y);` into `s &= ~z | y;` This patch turns this assembly from: ``` foo: not rcx and rsi, rdx andn rax, rsi, rdi or rcx, rdx and rax, rcx ret ``` into: ``` foo: and rsi, rdx andn rcx, rdx, rcx andn rax, rsi, rdi andn rax, rcx, rax ret ```
1 parent f00c946 commit 6621234

File tree

8 files changed

+45
-4
lines changed

8 files changed

+45
-4
lines changed

llvm/include/llvm/Analysis/TargetTransformInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,8 @@ class TargetTransformInfo {
823823
/// would typically be allowed using throughput or size cost models.
824824
bool hasDivRemOp(Type *DataType, bool IsSigned) const;
825825

826+
bool hasAndNot(Type *DataType) const;
827+
826828
/// Return true if the given instruction (assumed to be a memory access
827829
/// instruction) has a volatile variant. If that's the case then we can avoid
828830
/// addrspacecast to generic AS for volatile loads/stores. Default
@@ -1912,6 +1914,7 @@ class TargetTransformInfo::Concept {
19121914
const SmallBitVector &OpcodeMask) const = 0;
19131915
virtual bool enableOrderedReductions() = 0;
19141916
virtual bool hasDivRemOp(Type *DataType, bool IsSigned) = 0;
1917+
virtual bool hasAndNot(Type *DataType) = 0;
19151918
virtual bool hasVolatileVariant(Instruction *I, unsigned AddrSpace) = 0;
19161919
virtual bool prefersVectorizedAddressing() = 0;
19171920
virtual InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
@@ -2430,6 +2433,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
24302433
bool hasDivRemOp(Type *DataType, bool IsSigned) override {
24312434
return Impl.hasDivRemOp(DataType, IsSigned);
24322435
}
2436+
2437+
bool hasAndNot(Type *DataType) override { return Impl.hasAndNot(DataType); }
2438+
24332439
bool hasVolatileVariant(Instruction *I, unsigned AddrSpace) override {
24342440
return Impl.hasVolatileVariant(I, AddrSpace);
24352441
}

llvm/include/llvm/Analysis/TargetTransformInfoImpl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@ class TargetTransformInfoImplBase {
335335

336336
bool hasDivRemOp(Type *DataType, bool IsSigned) const { return false; }
337337

338+
bool hasAndNot(Type *DataType) const { return false; }
339+
338340
bool hasVolatileVariant(Instruction *I, unsigned AddrSpace) const {
339341
return false;
340342
}

llvm/include/llvm/Transforms/InstCombine/InstCombiner.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
526526
bool AllowMultipleUsers = false) = 0;
527527

528528
bool isValidAddrSpaceCast(unsigned FromAS, unsigned ToAS) const;
529+
bool hasAndNot(Type *DT) const;
529530
};
530531

531532
} // namespace llvm

llvm/lib/Analysis/TargetTransformInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ bool TargetTransformInfo::hasDivRemOp(Type *DataType, bool IsSigned) const {
530530
return TTIImpl->hasDivRemOp(DataType, IsSigned);
531531
}
532532

533+
bool TargetTransformInfo::hasAndNot(Type *DataType) const {
534+
return TTIImpl->hasAndNot(DataType);
535+
}
536+
533537
bool TargetTransformInfo::hasVolatileVariant(Instruction *I,
534538
unsigned AddrSpace) const {
535539
return TTIImpl->hasVolatileVariant(I, AddrSpace);

llvm/lib/Target/X86/X86TargetTransformInfo.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6250,6 +6250,28 @@ bool X86TTIImpl::hasDivRemOp(Type *DataType, bool IsSigned) {
62506250
return TLI->isOperationLegal(IsSigned ? ISD::SDIVREM : ISD::UDIVREM, VT);
62516251
}
62526252

6253+
bool X86TTIImpl::hasAndNot(Type *DataType) {
6254+
EVT VT = TLI->getValueType(DL, DataType);
6255+
6256+
if (VT.isVector()) {
6257+
if (!ST->hasSSE1() || VT.getSizeInBits() < 128)
6258+
return false;
6259+
6260+
if (VT == MVT::v4i32)
6261+
return false;
6262+
6263+
return ST->hasSSE2();
6264+
}
6265+
6266+
if (!ST->hasBMI())
6267+
return false;
6268+
6269+
if (VT != MVT::i32 && VT != MVT::i64)
6270+
return false;
6271+
6272+
return true;
6273+
}
6274+
62536275
bool X86TTIImpl::isExpensiveToSpeculativelyExecute(const Instruction* I) {
62546276
// FDIV is always expensive, even if it has a very low uop count.
62556277
// TODO: Still necessary for recent CPUs with low latency/throughput fdiv?

llvm/lib/Target/X86/X86TargetTransformInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ class X86TTIImpl : public BasicTTIImplBase<X86TTIImpl> {
277277
bool isLegalAltInstr(VectorType *VecTy, unsigned Opcode0, unsigned Opcode1,
278278
const SmallBitVector &OpcodeMask) const;
279279
bool hasDivRemOp(Type *DataType, bool IsSigned);
280+
bool hasAndNot(Type *DataType);
280281
bool isExpensiveToSpeculativelyExecute(const Instruction *I);
281282
bool isFCmpOrdCheaperThanFCmpZero(Type *Ty);
282283
bool areInlineCompatible(const Function *Caller,

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,8 +2630,9 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
26302630
if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I))
26312631
return FoldedLogic;
26322632

2633-
if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
2634-
return DeMorgan;
2633+
if (!hasAndNot(I.getType()))
2634+
if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
2635+
return DeMorgan;
26352636

26362637
{
26372638
Value *A, *B, *C;
@@ -4486,11 +4487,13 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
44864487
// those are handled via SimplifySelectsFeedingBinaryOp().
44874488
Type *Ty = I.getType();
44884489
Value *X, *Y;
4489-
if (match(NotOp, m_OneUse(m_c_And(m_Not(m_Value(X)), m_Value(Y))))) {
4490+
if (match(NotOp, m_OneUse(m_c_And(m_Not(m_Value(X)), m_Value(Y)))) &&
4491+
!hasAndNot(Ty)) {
44904492
Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
44914493
return BinaryOperator::CreateOr(X, NotY);
44924494
}
4493-
if (match(NotOp, m_OneUse(m_LogicalAnd(m_Not(m_Value(X)), m_Value(Y))))) {
4495+
if (match(NotOp, m_OneUse(m_LogicalAnd(m_Not(m_Value(X)), m_Value(Y)))) &&
4496+
!hasAndNot(Ty)) {
44944497
Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
44954498
return SelectInst::Create(X, ConstantInt::getTrue(Ty), NotY);
44964499
}

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ bool InstCombiner::isValidAddrSpaceCast(unsigned FromAS, unsigned ToAS) const {
189189
return TTI.isValidAddrSpaceCast(FromAS, ToAS);
190190
}
191191

192+
bool InstCombiner::hasAndNot(Type *DT) const { return TTI.hasAndNot(DT); }
193+
192194
Value *InstCombinerImpl::EmitGEPOffset(GEPOperator *GEP, bool RewriteGEP) {
193195
if (!RewriteGEP)
194196
return llvm::emitGEPOffset(&Builder, DL, GEP);

0 commit comments

Comments
 (0)