diff options
author | Sanjay Patel <spatel@rotateright.com> | 2018-07-02 17:42:29 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2018-07-02 17:42:29 +0000 |
commit | b999d7413298bc8288e7f676b65ba1e74764c578 (patch) | |
tree | 939f6e5cac82c2c60d0ef24e3fafe2e5f0ffd29c /llvm/lib | |
parent | 4d5b1073ba87f6709112d0d9b5270ee51d3abd54 (diff) | |
download | bcm5719-llvm-b999d7413298bc8288e7f676b65ba1e74764c578.tar.gz bcm5719-llvm-b999d7413298bc8288e7f676b65ba1e74764c578.zip |
[InstCombine] reverse canonicalization of add --> or to allow more shuffle folding
This extends D48485 to allow another pair of binops (add/or) to be combined either
with or without a leading shuffle:
or X, C --> add X, C (when X and C have no common bits set)
Here, we need value tracking to determine that the 'or' can be reversed into an 'add',
and we've added general infrastructure to allow extending to other opcodes or moving
to where other passes could use that functionality.
Differential Revision: https://reviews.llvm.org/D48662
llvm-svn: 336128
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp | 67 |
1 files changed, 55 insertions, 12 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index dd579a66325..b06889f182d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -1140,9 +1140,52 @@ static bool isShuffleExtractingFromLHS(ShuffleVectorInst &SVI, return true; } +/// These are the ingredients in an alternate form binary operator as described +/// below. +struct BinopElts { + BinaryOperator::BinaryOps Opcode; + Value *Op0; + Value *Op1; + BinopElts(BinaryOperator::BinaryOps Opc = (BinaryOperator::BinaryOps)0, + Value *V0 = nullptr, Value *V1 = nullptr) : + Opcode(Opc), Op0(V0), Op1(V1) {} + operator bool() const { return Opcode != 0; } +}; + +/// Binops may be transformed into binops with different opcodes and operands. +/// Reverse the usual canonicalization to enable folds with the non-canonical +/// form of the binop. If a transform is possible, return the elements of the +/// new binop. If not, return invalid elements. +static BinopElts getAlternateBinop(BinaryOperator *BO, const DataLayout &DL) { + Value *BO0 = BO->getOperand(0), *BO1 = BO->getOperand(1); + Type *Ty = BO->getType(); + switch (BO->getOpcode()) { + case Instruction::Shl: { + // shl X, C --> mul X, (1 << C) + Constant *C; + if (match(BO1, m_Constant(C))) { + Constant *ShlOne = ConstantExpr::getShl(ConstantInt::get(Ty, 1), C); + return { Instruction::Mul, BO0, ShlOne }; + } + break; + } + case Instruction::Or: { + // or X, C --> add X, C (when X and C have no common bits set) + const APInt *C; + if (match(BO1, m_APInt(C)) && MaskedValueIsZero(BO0, *C, DL)) + return { Instruction::Add, BO0, BO1 }; + break; + } + default: + break; + } + return {}; +} + +/// Try to fold shuffles that are the equivalent of a vector select. static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf, - InstCombiner::BuilderTy &Builder) { - // Folds under here require the equivalent of a vector select. + InstCombiner::BuilderTy &Builder, + const DataLayout &DL) { if (!Shuf.isSelect()) return nullptr; @@ -1168,19 +1211,19 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf, BinaryOperator::BinaryOps Opc1 = B1->getOpcode(); bool DropNSW = false; if (ConstantsAreOp1 && Opc0 != Opc1) { - // If we have multiply and shift-left-by-constant, convert the shift: - // shl X, C --> mul X, 1 << C // TODO: We drop "nsw" if shift is converted into multiply because it may // not be correct when the shift amount is BitWidth - 1. We could examine // each vector element to determine if it is safe to keep that flag. - if (Opc0 == Instruction::Mul && Opc1 == Instruction::Shl) { - C1 = ConstantExpr::getShl(ConstantInt::get(C1->getType(), 1), C1); - Opc1 = Instruction::Mul; - DropNSW = true; - } else if (Opc0 == Instruction::Shl && Opc1 == Instruction::Mul) { - C0 = ConstantExpr::getShl(ConstantInt::get(C0->getType(), 1), C0); - Opc0 = Instruction::Mul; + if (Opc0 == Instruction::Shl || Opc1 == Instruction::Shl) DropNSW = true; + if (BinopElts AltB0 = getAlternateBinop(B0, DL)) { + assert(isa<Constant>(AltB0.Op1) && "Expecting constant with alt binop"); + Opc0 = AltB0.Opcode; + C0 = cast<Constant>(AltB0.Op1); + } else if (BinopElts AltB1 = getAlternateBinop(B1, DL)) { + assert(isa<Constant>(AltB1.Op1) && "Expecting constant with alt binop"); + Opc1 = AltB1.Opcode; + C1 = cast<Constant>(AltB1.Op1); } } @@ -1249,7 +1292,7 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { LHS, RHS, SVI.getMask(), SVI.getType(), SQ.getWithInstruction(&SVI))) return replaceInstUsesWith(SVI, V); - if (Instruction *I = foldSelectShuffle(SVI, Builder)) + if (Instruction *I = foldSelectShuffle(SVI, Builder, DL)) return I; bool MadeChange = false; |