[IR][GVN] add/allow commutative intrinsics with >2 args

Follow-up to D86798 and rGe25449f.
This commit is contained in:
Sanjay Patel 2020-09-03 10:12:59 -04:00
parent 4013cfd34d
commit bdd5bfd0e4
3 changed files with 12 additions and 19 deletions

View File

@ -70,13 +70,12 @@ public:
case Intrinsic::uadd_with_overflow:
case Intrinsic::smul_with_overflow:
case Intrinsic::umul_with_overflow:
// TODO: These fixed-point math intrinsics have commutative first two
// operands, but callers may not handle instructions with more than
// two operands.
// case Intrinsic::smul_fix:
// case Intrinsic::umul_fix:
// case Intrinsic::smul_fix_sat:
// case Intrinsic::umul_fix_sat:
case Intrinsic::smul_fix:
case Intrinsic::umul_fix:
case Intrinsic::smul_fix_sat:
case Intrinsic::umul_fix_sat:
case Intrinsic::fma:
case Intrinsic::fmuladd:
return true;
default:
return false;

View File

@ -295,9 +295,7 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) {
// of their operands get the same value number by sorting the operand value
// numbers. Since commutative operands are the 1st two operands it is more
// efficient to sort by hand rather than using, say, std::sort.
assert(((isa<BinaryOperator>(I) && I->getNumOperands() == 2) ||
(isa<IntrinsicInst>(I) && I->getNumOperands() == 3))
&& "Unsupported commutative instruction!");
assert(I->getNumOperands() >= 2 && "Unsupported commutative instruction!");
if (e.varargs[0] > e.varargs[1])
std::swap(e.varargs[0], e.varargs[1]);
e.commutative = true;
@ -1840,9 +1838,7 @@ uint32_t GVN::ValueTable::phiTranslateImpl(const BasicBlock *Pred,
}
if (Exp.commutative) {
assert((Exp.varargs.size() == 2 ||
(Exp.opcode == Instruction::Call && Exp.varargs.size() == 3))
&& "Unsupported commutative instruction!");
assert(Exp.varargs.size() >= 2 && "Unsupported commutative instruction!");
if (Exp.varargs[0] > Exp.varargs[1]) {
std::swap(Exp.varargs[0], Exp.varargs[1]);
uint32_t Opcode = Exp.opcode >> 8;

View File

@ -74,9 +74,7 @@ declare i16 @llvm.umul.fix.i16(i16, i16, i32)
define i16 @intrinsic_3_args(i16 %x, i16 %y) {
; CHECK-LABEL: @intrinsic_3_args(
; CHECK-NEXT: [[M1:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[X:%.*]], i16 [[Y:%.*]], i32 1)
; CHECK-NEXT: [[M2:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[Y]], i16 [[X]], i32 1)
; CHECK-NEXT: [[R:%.*]] = sub i16 [[M1]], [[M2]]
; CHECK-NEXT: ret i16 [[R]]
; CHECK-NEXT: ret i16 0
;
%m1 = call i16 @llvm.smul.fix.i16(i16 %x, i16 %y, i32 1)
%m2 = call i16 @llvm.smul.fix.i16(i16 %y, i16 %x, i32 1)
@ -84,6 +82,8 @@ define i16 @intrinsic_3_args(i16 %x, i16 %y) {
ret i16 %r
}
; Negative test - 3rd arg is different
define i16 @intrinsic_3_args_not_same(i16 %x, i16 %y) {
; CHECK-LABEL: @intrinsic_3_args_not_same(
; CHECK-NEXT: [[M1:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[X:%.*]], i16 [[Y:%.*]], i32 2)
@ -102,9 +102,7 @@ declare float @llvm.fma.f32(float, float, float)
define float @fma(float %x, float %y) {
; CHECK-LABEL: @fma(
; CHECK-NEXT: [[M1:%.*]] = call float @llvm.fma.f32(float [[X:%.*]], float [[Y:%.*]], float 1.000000e+00)
; CHECK-NEXT: [[M2:%.*]] = call float @llvm.fma.f32(float [[Y]], float [[X]], float 1.000000e+00)
; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[M1]], [[M2]]
; CHECK-NEXT: ret float [[R]]
; CHECK-NEXT: ret float 1.000000e+00
;
%m1 = call float @llvm.fma.f32(float %x, float %y, float 1.0)
%m2 = call float @llvm.fma.f32(float %y, float %x, float 1.0)