[llvm] r321366 - [InlineCost] Find more free binary operations

Haicheng Wu via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 22 09:09:09 PST 2017


Author: haicheng
Date: Fri Dec 22 09:09:09 2017
New Revision: 321366

URL: http://llvm.org/viewvc/llvm-project?rev=321366&view=rev
Log:
[InlineCost] Find more free binary operations

Currently, inline cost model considers a binary operator as free only if both
its operands are constants. Some simple cases are missing such as a + 0, a - a,
etc. This patch modifies visitBinaryOperator() to call SimplifyBinOp() without
going through simplifyInstruction() to get rid of the constant restriction.
Thus, visitAnd() and visitOr() are not needed.

Differential Revision: https://reviews.llvm.org/D41494

Added:
    llvm/trunk/test/Transforms/Inline/AArch64/binop.ll
Modified:
    llvm/trunk/lib/Analysis/InlineCost.cpp

Modified: llvm/trunk/lib/Analysis/InlineCost.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InlineCost.cpp?rev=321366&r1=321365&r2=321366&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InlineCost.cpp (original)
+++ llvm/trunk/lib/Analysis/InlineCost.cpp Fri Dec 22 09:09:09 2017
@@ -249,8 +249,6 @@ class CallAnalyzer : public InstVisitor<
   bool visitCastInst(CastInst &I);
   bool visitUnaryInstruction(UnaryInstruction &I);
   bool visitCmpInst(CmpInst &I);
-  bool visitAnd(BinaryOperator &I);
-  bool visitOr(BinaryOperator &I);
   bool visitSub(BinaryOperator &I);
   bool visitBinaryOperator(BinaryOperator &I);
   bool visitLoad(LoadInst &I);
@@ -1021,34 +1019,6 @@ bool CallAnalyzer::visitCmpInst(CmpInst
   return false;
 }
 
-bool CallAnalyzer::visitOr(BinaryOperator &I) {
-  // This is necessary because the generic simplify instruction only works if
-  // both operands are constants.
-  for (unsigned i = 0; i < 2; ++i) {
-    if (ConstantInt *C = dyn_cast_or_null<ConstantInt>(
-            SimplifiedValues.lookup(I.getOperand(i))))
-      if (C->isAllOnesValue()) {
-        SimplifiedValues[&I] = C;
-        return true;
-      }
-  }
-  return Base::visitOr(I);
-}
-
-bool CallAnalyzer::visitAnd(BinaryOperator &I) {
-  // This is necessary because the generic simplify instruction only works if
-  // both operands are constants.
-  for (unsigned i = 0; i < 2; ++i) {
-    if (ConstantInt *C = dyn_cast_or_null<ConstantInt>(
-            SimplifiedValues.lookup(I.getOperand(i))))
-      if (C->isZero()) {
-        SimplifiedValues[&I] = C;
-        return true;
-      }
-  }
-  return Base::visitAnd(I);
-}
-
 bool CallAnalyzer::visitSub(BinaryOperator &I) {
   // Try to handle a special case: we can fold computing the difference of two
   // constant-related pointers.
@@ -1078,17 +1048,25 @@ bool CallAnalyzer::visitSub(BinaryOperat
 
 bool CallAnalyzer::visitBinaryOperator(BinaryOperator &I) {
   Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
-  auto Evaluate = [&](SmallVectorImpl<Constant *> &COps) {
-    Value *SimpleV = nullptr;
-    if (auto FI = dyn_cast<FPMathOperator>(&I))
-      SimpleV = SimplifyFPBinOp(I.getOpcode(), COps[0], COps[1],
-                                FI->getFastMathFlags(), DL);
-    else
-      SimpleV = SimplifyBinOp(I.getOpcode(), COps[0], COps[1], DL);
-    return dyn_cast_or_null<Constant>(SimpleV);
-  };
+  Constant *CLHS = dyn_cast<Constant>(LHS);
+  if (!CLHS)
+    CLHS = SimplifiedValues.lookup(LHS);
+  Constant *CRHS = dyn_cast<Constant>(RHS);
+  if (!CRHS)
+    CRHS = SimplifiedValues.lookup(RHS);
+
+  Value *SimpleV = nullptr;
+  if (auto FI = dyn_cast<FPMathOperator>(&I))
+    SimpleV = SimplifyFPBinOp(I.getOpcode(), CLHS ? CLHS : LHS,
+                              CRHS ? CRHS : RHS, FI->getFastMathFlags(), DL);
+  else
+    SimpleV =
+        SimplifyBinOp(I.getOpcode(), CLHS ? CLHS : LHS, CRHS ? CRHS : RHS, DL);
+
+  if (Constant *C = dyn_cast_or_null<Constant>(SimpleV))
+    SimplifiedValues[&I] = C;
 
-  if (simplifyInstruction(I, Evaluate))
+  if (SimpleV)
     return true;
 
   // Disable any SROA on arguments to arbitrary, unsimplified binary operators.

Added: llvm/trunk/test/Transforms/Inline/AArch64/binop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/AArch64/binop.ll?rev=321366&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/Inline/AArch64/binop.ll (added)
+++ llvm/trunk/test/Transforms/Inline/AArch64/binop.ll Fri Dec 22 09:09:09 2017
@@ -0,0 +1,291 @@
+; RUN: opt -inline -mtriple=aarch64--linux-gnu -S -o - < %s -inline-threshold=0 | FileCheck %s
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64--linux-gnu"
+
+declare void @pad()
+ at glbl = external global i32
+
+define i32 @outer_add1(i32 %a) {
+; CHECK-LABEL: @outer_add1(
+; CHECK-NOT: call i32 @add
+  %C = call i32 @add(i32 %a, i32 0)
+  ret i32 %C
+}
+
+define i32 @outer_add2(i32 %a) {
+; CHECK-LABEL: @outer_add2(
+; CHECK-NOT: call i32 @add
+  %C = call i32 @add(i32 0, i32 %a)
+  ret i32 %C
+}
+
+define i32 @add(i32 %a, i32 %b) {
+  %add = add i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %add
+}
+
+
+
+define i32 @outer_sub1(i32 %a) {
+; CHECK-LABEL: @outer_sub1(
+; CHECK-NOT: call i32 @sub1
+  %C = call i32 @sub1(i32 %a, i32 0)
+  ret i32 %C
+}
+
+define i32 @sub1(i32 %a, i32 %b) {
+  %sub = sub i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %sub
+}
+
+
+define i32 @outer_sub2(i32 %a) {
+; CHECK-LABEL: @outer_sub2(
+; CHECK-NOT: call i32 @sub2
+  %C = call i32 @sub2(i32 %a)
+  ret i32 %C
+}
+
+define i32 @sub2(i32 %a) {
+  %sub = sub i32 %a, %a
+  call void @pad()
+  ret i32 %sub
+}
+
+
+
+define i32 @outer_mul1(i32 %a) {
+; CHECK-LABEL: @outer_mul1(
+; CHECK-NOT: call i32 @mul
+  %C = call i32 @mul(i32 %a, i32 0)
+  ret i32 %C
+}
+
+define i32 @outer_mul2(i32 %a) {
+; CHECK-LABEL: @outer_mul2(
+; CHECK-NOT: call i32 @mul
+  %C = call i32 @mul(i32 %a, i32 1)
+  ret i32 %C
+}
+
+define i32 @mul(i32 %a, i32 %b) {
+  %mul = mul i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %mul
+}
+
+
+
+define i32 @outer_div1(i32 %a) {
+; CHECK-LABEL: @outer_div1(
+; CHECK-NOT: call i32 @div1
+  %C = call i32 @div1(i32 0, i32 %a)
+  ret i32 %C
+}
+
+define i32 @outer_div2(i32 %a) {
+; CHECK-LABEL: @outer_div2(
+; CHECK-NOT: call i32 @div1
+  %C = call i32 @div1(i32 %a, i32 1)
+  ret i32 %C
+}
+
+define i32 @div1(i32 %a, i32 %b) {
+  %div = sdiv i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %div
+}
+
+
+define i32 @outer_div3(i32 %a) {
+; CHECK-LABEL: @outer_div3(
+; CHECK-NOT: call i32 @div
+  %C = call i32 @div2(i32 %a)
+  ret i32 %C
+}
+
+define i32 @div2(i32 %a) {
+  %div = sdiv i32 %a, %a
+  call void @pad()
+  ret i32 %div
+}
+
+
+
+define i32 @outer_rem1(i32 %a) {
+; CHECK-LABEL: @outer_rem1(
+; CHECK-NOT: call i32 @rem
+  %C = call i32 @rem1(i32 0, i32 %a)
+  ret i32 %C
+}
+
+define i32 @outer_rem2(i32 %a) {
+; CHECK-LABEL: @outer_rem2(
+; CHECK-NOT: call i32 @rem
+  %C = call i32 @rem1(i32 %a, i32 1)
+  ret i32 %C
+}
+
+define i32 @rem1(i32 %a, i32 %b) {
+  %rem = urem i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %rem
+}
+
+
+define i32 @outer_rem3(i32 %a) {
+; CHECK-LABEL: @outer_rem3(
+; CHECK-NOT: call i32 @rem
+  %C = call i32 @rem2(i32 %a)
+  ret i32 %C
+}
+
+define i32 @rem2(i32 %a) {
+  %rem = urem i32 %a, %a
+  call void @pad()
+  ret i32 %rem
+}
+
+
+
+define i32 @outer_shl1(i32 %a) {
+; CHECK-LABEL: @outer_shl1(
+; CHECK-NOT: call i32 @shl
+  %C = call i32 @shl(i32 %a, i32 0)
+  ret i32 %C
+}
+
+define i32 @shl(i32 %a, i32 %b) {
+  %shl = shl i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %shl
+}
+
+
+
+define i32 @outer_shr1(i32 %a) {
+; CHECK-LABEL: @outer_shr1(
+; CHECK-NOT: call i32 @shr
+  %C = call i32 @shr(i32 %a, i32 0)
+  ret i32 %C
+}
+
+define i32 @shr(i32 %a, i32 %b) {
+  %shr = ashr i32 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i32 %shr
+}
+
+
+
+define i1 @outer_and1(i1 %a) {
+; check-label: @outer_and1(
+; check-not: call i1 @and1
+  %c = call i1 @and1(i1 %a, i1 false)
+  ret i1 %c
+}
+
+define i1 @outer_and2(i1 %a) {
+; check-label: @outer_and2(
+; check-not: call i1 @and1
+  %c = call i1 @and1(i1 %a, i1 true)
+  ret i1 %c
+}
+
+define i1 @and1(i1 %a, i1 %b) {
+  %and = and i1 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i1 %and
+}
+
+
+define i1 @outer_and3(i1 %a) {
+; check-label: @outer_and3(
+; check-not: call i1 @and2
+  %c = call i1 @and2(i1 %a)
+  ret i1 %c
+}
+
+define i1 @and2(i1 %a) {
+  %and = and i1 %a, %a
+  call void @pad()
+  ret i1 %and
+}
+
+
+
+define i1 @outer_or1(i1 %a) {
+; check-label: @outer_or1(
+; check-not: call i1 @or1
+  %c = call i1 @or1(i1 %a, i1 false)
+  ret i1 %c
+}
+
+define i1 @outer_or2(i1 %a) {
+; check-label: @outer_or2(
+; check-not: call i1 @or1
+  %c = call i1 @or1(i1 %a, i1 true)
+  ret i1 %c
+}
+
+define i1 @or1(i1 %a, i1 %b) {
+  %or = or i1 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i1 %or
+}
+
+
+define i1 @outer_or3(i1 %a) {
+; check-label: @outer_or3(
+; check-not: call i1 @or2
+  %c = call i1 @or2(i1 %a)
+  ret i1 %c
+}
+
+define i1 @or2(i1 %a) {
+  %or = or i1 %a, %a
+  call void @pad()
+  ret i1 %or
+}
+
+
+
+define i1 @outer_xor1(i1 %a) {
+; check-label: @outer_xor1(
+; check-not: call i1 @xor
+  %c = call i1 @xor1(i1 %a, i1 false)
+  ret i1 %c
+}
+
+define i1 @xor1(i1 %a, i1 %b) {
+  %xor = xor i1 %a, %b
+  call void @pad()
+  store i32 0, i32* @glbl
+  ret i1 %xor
+}
+
+
+define i1 @outer_xor3(i1 %a) {
+; check-label: @outer_xor3(
+; check-not: call i1 @xor
+  %c = call i1 @xor2(i1 %a)
+  ret i1 %c
+}
+
+define i1 @xor2(i1 %a) {
+  %xor = xor i1 %a, %a
+  call void @pad()
+  ret i1 %xor
+}




More information about the llvm-commits mailing list