diff options
Diffstat (limited to 'llvm/lib/Transforms')
-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; |