diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index a03eac0ad40d6d..ceec001dccf46b 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -532,7 +532,7 @@ class Instruction : public User, /// In LLVM, these are the commutative operators, plus SetEQ and SetNE, when /// applied to any type. /// - bool isCommutative() const { return isCommutative(getOpcode()); } + bool isCommutative() const LLVM_READONLY; static bool isCommutative(unsigned Opcode) { switch (Opcode) { case Add: case FAdd: diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 3a67185bef31dd..794a73ed28e944 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -673,6 +673,13 @@ bool Instruction::isAssociative() const { } } +bool Instruction::isCommutative() const { + if (auto *II = dyn_cast(this)) + return II->isCommutative(); + // TODO: Should allow icmp/fcmp? + return isCommutative(getOpcode()); +} + unsigned Instruction::getNumSuccessors() const { switch (getOpcode()) { #define HANDLE_TERM_INST(N, OPC, CLASS) \ diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp index f51596525569ca..ff7596b19cb2b0 100644 --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -291,9 +291,11 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) { if (I->isCommutative()) { // Ensure that commutative instructions that only differ by a permutation // of their operands get the same value number by sorting the operand value - // numbers. Since all commutative instructions have two operands it is more + // numbers. Since commutative operands are the 1st two operands it is more // efficient to sort by hand rather than using, say, std::sort. - assert(I->getNumOperands() == 2 && "Unsupported commutative instruction!"); + assert(((isa(I) && I->getNumOperands() == 2) || + (isa(I) && I->getNumOperands() == 3)) + && "Unsupported commutative instruction!"); if (e.varargs[0] > e.varargs[1]) std::swap(e.varargs[0], e.varargs[1]); e.commutative = true; @@ -1806,7 +1808,9 @@ uint32_t GVN::ValueTable::phiTranslateImpl(const BasicBlock *Pred, } if (Exp.commutative) { - assert(Exp.varargs.size() == 2 && "Unsupported commutative expression!"); + assert((Exp.varargs.size() == 2 || + (Exp.opcode == Instruction::Call && Exp.varargs.size() == 3)) + && "Unsupported commutative instruction!"); if (Exp.varargs[0] > Exp.varargs[1]) { std::swap(Exp.varargs[0], Exp.varargs[1]); uint32_t Opcode = Exp.opcode >> 8; diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp index e7fd201d70e470..f422d1b51b991c 100644 --- a/llvm/lib/Transforms/Scalar/NewGVN.cpp +++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp @@ -1254,6 +1254,7 @@ const UnknownExpression *NewGVN::createUnknownExpression(Instruction *I) const { const CallExpression * NewGVN::createCallExpression(CallInst *CI, const MemoryAccess *MA) const { // FIXME: Add operand bundles for calls. + // FIXME: Allow commutative matching for intrinsics. auto *E = new (ExpressionAllocator) CallExpression(CI->getNumOperands(), CI, MA); setBasicExpressionInfo(CI, E); diff --git a/llvm/test/Transforms/GVN/commute.ll b/llvm/test/Transforms/GVN/commute.ll index 2e6d7274ead96a..72506c0ece283c 100644 --- a/llvm/test/Transforms/GVN/commute.ll +++ b/llvm/test/Transforms/GVN/commute.ll @@ -34,8 +34,7 @@ declare i32 @llvm.umax.i32(i32, i32) define void @intrinsic(i32 %x, i32 %y) { ; CHECK-LABEL: @intrinsic( ; CHECK-NEXT: [[M1:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 [[Y:%.*]]) -; CHECK-NEXT: [[M2:%.*]] = call i32 @llvm.umax.i32(i32 [[Y]], i32 [[X]]) -; CHECK-NEXT: call void @use(i32 [[M1]], i32 [[M2]]) +; CHECK-NEXT: call void @use(i32 [[M1]], i32 [[M1]]) ; CHECK-NEXT: ret void ; %m1 = call i32 @llvm.umax.i32(i32 %x, i32 %y)