diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h index 3b16aa039a508..15b90589b7e2b 100644 --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -1210,8 +1210,11 @@ class ConstantExpr : public Constant { /// Return the absorbing element for the given binary /// operation, i.e. a constant C such that X op C = C and C op X = C for /// every X. For example, this returns zero for integer multiplication. - /// It returns null if the operator doesn't have an absorbing element. - static Constant *getBinOpAbsorber(unsigned Opcode, Type *Ty); + /// If AllowLHSConstant is true, the LHS operand is a constant C that must be + /// defined as C op X = C. It returns null if the operator doesn't have + /// an absorbing element. + static Constant *getBinOpAbsorber(unsigned Opcode, Type *Ty, + bool AllowLHSConstant = false); /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp index 05ab0968ef6f3..a6f46da313e21 100644 --- a/llvm/lib/IR/ConstantFold.cpp +++ b/llvm/lib/IR/ConstantFold.cpp @@ -731,11 +731,11 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, // Handle simplifications when the RHS is a constant int. if (ConstantInt *CI2 = dyn_cast(C2)) { + if (C2 == ConstantExpr::getBinOpAbsorber(Opcode, C2->getType(), + /*AllowLHSConstant*/ false)) + return C2; + switch (Opcode) { - case Instruction::Mul: - if (CI2->isZero()) - return C2; // X * 0 == 0 - break; case Instruction::UDiv: case Instruction::SDiv: if (CI2->isZero()) @@ -749,9 +749,7 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, return PoisonValue::get(CI2->getType()); // X % 0 == poison break; case Instruction::And: - if (CI2->isZero()) - return C2; // X & 0 == 0 - + assert(!CI2->isZero() && "And zero handled above"); if (ConstantExpr *CE1 = dyn_cast(C1)) { // If and'ing the address of a global with a constant, fold it. if (CE1->getOpcode() == Instruction::PtrToInt && @@ -791,10 +789,6 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, } } break; - case Instruction::Or: - if (CI2->isMinusOne()) - return C2; // X | -1 == -1 - break; } } else if (isa(C1)) { // If C1 is a ConstantInt and C2 is not, swap the operands. @@ -854,19 +848,9 @@ Constant *llvm::ConstantFoldBinaryInstruction(unsigned Opcode, Constant *C1, } } - switch (Opcode) { - case Instruction::SDiv: - case Instruction::UDiv: - case Instruction::URem: - case Instruction::SRem: - case Instruction::LShr: - case Instruction::AShr: - case Instruction::Shl: - if (CI1->isZero()) return C1; - break; - default: - break; - } + if (C1 == ConstantExpr::getBinOpAbsorber(Opcode, C1->getType(), + /*AllowLHSConstant*/ true)) + return C1; } else if (ConstantFP *CFP1 = dyn_cast(C1)) { if (ConstantFP *CFP2 = dyn_cast(C2)) { const APFloat &C1V = CFP1->getValueAPF(); diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index d6c00a4b54782..fe3a086c5772d 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -2735,17 +2735,34 @@ Constant *ConstantExpr::getIdentity(Instruction *I, Type *Ty, return nullptr; } -Constant *ConstantExpr::getBinOpAbsorber(unsigned Opcode, Type *Ty) { +Constant *ConstantExpr::getBinOpAbsorber(unsigned Opcode, Type *Ty, + bool AllowLHSConstant) { switch (Opcode) { default: - // Doesn't have an absorber. - return nullptr; + break; - case Instruction::Or: + case Instruction::Or: // -1 | X = -1 return Constant::getAllOnesValue(Ty); - case Instruction::And: - case Instruction::Mul: + case Instruction::And: // 0 & X = 0 + case Instruction::Mul: // 0 * X = 0 + return Constant::getNullValue(Ty); + } + + // AllowLHSConstant must be set. + if (!AllowLHSConstant) + return nullptr; + + switch (Opcode) { + default: + return nullptr; + case Instruction::Shl: // 0 << X = 0 + case Instruction::LShr: // 0 >>l X = 0 + case Instruction::AShr: // 0 >>a X = 0 + case Instruction::SDiv: // 0 /s X = 0 + case Instruction::UDiv: // 0 /u X = 0 + case Instruction::URem: // 0 %u X = 0 + case Instruction::SRem: // 0 %s X = 0 return Constant::getNullValue(Ty); } }