Aggressive LEA

Convert adds with a constant operand to lea on -aggressive-lea

BUG=none
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/2135403002 .
diff --git a/src/IceClFlags.def b/src/IceClFlags.def
index d5e1a26..f13afbe 100644
--- a/src/IceClFlags.def
+++ b/src/IceClFlags.def
@@ -95,6 +95,10 @@
     cl::desc("Exit with success status, even if errors found"),                \
     cl::init(false))                                                           \
                                                                                \
+  X(AggressiveLea, bool, dev_opt_flag, "aggressive-lea",                       \
+    cl::desc("Convert additions to lea when it reduces code size"),            \
+    cl::init(false))                                                           \
+                                                                               \
   X(BitcodeAsText, bool, dev_opt_flag, "bitcode-as-text",                      \
     cl::desc("Accept textual form of PNaCl bitcode "                           \
              "records (i.e. not .ll assembly)"),                               \
diff --git a/src/IceInstX86Base.h b/src/IceInstX86Base.h
index de7d2f7..1221351 100644
--- a/src/IceInstX86Base.h
+++ b/src/IceInstX86Base.h
@@ -622,6 +622,13 @@
       Type Ty = Var->getType();
       const Operand *Src = this->getSrc(0);
       constexpr bool IsLea = K == InstX86Base::Lea;
+
+      if (IsLea) {
+        if (auto *Add = deoptLeaToAddOrNull(Func)) {
+          Add->emitIAS(Func);
+          return;
+        }
+      }
       emitIASRegOpTyGPR(Func, IsLea, Ty, Var, Src, Emitter);
     }
     void dump(const Cfg *Func) const override {
@@ -632,6 +639,7 @@
       Str << " = " << Opcode << "." << this->getSrc(0)->getType() << " ";
       this->dumpSources(Func);
     }
+
     static bool classof(const Inst *Instr) {
       return InstX86Base::isClassof(Instr, InstX86Base::K);
     }
@@ -642,6 +650,23 @@
       this->addSource(Src);
     }
 
+    Inst *deoptLeaToAddOrNull(const Cfg *Func) const {
+      // Revert back to Add when the Lea is a 2-address instruction.
+      // Caller has to emit, this just produces the add instruction.
+      if (auto *MemOp = llvm::dyn_cast<X86OperandMem>(this->getSrc(0))) {
+        if (getFlags().getAggressiveLea() &&
+            MemOp->getBase()->getRegNum() == this->getDest()->getRegNum() &&
+            MemOp->getIndex() == nullptr && MemOp->getShift() == 0) {
+          auto *Add = InstImpl<TraitsType>::InstX86Add::create(
+              const_cast<Cfg *>(Func), this->getDest(), MemOp->getOffset());
+          // TODO(manasijm): Remove const_cast by emitting code for add
+          // directly.
+          return Add;
+        }
+      }
+      return nullptr;
+    }
+
     static const char *Opcode;
     static const GPREmitterRegOp Emitter;
   };
diff --git a/src/IceInstX86BaseImpl.h b/src/IceInstX86BaseImpl.h
index cfc36d4..4b9ea41 100644
--- a/src/IceInstX86BaseImpl.h
+++ b/src/IceInstX86BaseImpl.h
@@ -2025,6 +2025,11 @@
 void InstImpl<TraitsType>::InstX86Lea::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
+  if (auto *Add = this->deoptLeaToAddOrNull(Func)) {
+    Add->emit(Func);
+    return;
+  }
+
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(this->getSrcSize() == 1);
   assert(this->getDest()->hasReg());
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index a3df730..1562e4e 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -2187,11 +2187,25 @@
   case InstArithmetic::_num:
     llvm_unreachable("Unknown arithmetic operator");
     break;
-  case InstArithmetic::Add:
+  case InstArithmetic::Add: {
+    const bool ValidType =
+        Ty == IceType_i32 || (Ty == IceType_i64 && Traits::Is64Bit);
+    auto *Const = llvm::dyn_cast<Constant>(Instr->getSrc(1));
+    const bool ValidKind =
+        Const != nullptr && (llvm::isa<ConstantInteger32>(Const) ||
+                             llvm::isa<ConstantRelocatable>(Const));
+    if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
+      auto *Var = legalizeToReg(Src0);
+      auto *Mem = Traits::X86OperandMem::create(Func, IceType_void, Var, Const);
+      T = makeReg(Ty);
+      _lea(T, _sandbox_mem_reference(Mem));
+      _mov(Dest, T);
+      break;
+    }
     _mov(T, Src0);
     _add(T, Src1);
     _mov(Dest, T);
-    break;
+  } break;
   case InstArithmetic::And:
     _mov(T, Src0);
     _and(T, Src1);