Subzero: address mode opt: Transform *(reg+const) into [reg+const].

Teach address mode optimization about Base=Base+Const,
Base=Const+Base, and Base=Base-Const patterns.

Change ConstantInteger::emit() to emit signed values.

BUG=none
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/459133002
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 26d11b9..de033a5 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -3388,6 +3388,33 @@
       }
     }
 
+    // Base is Base=Var+Const || Base is Base=Const+Var ==>
+    //   set Base=Var, Offset+=Const
+    // Base is Base=Var-Const ==>
+    //   set Base=Var, Offset-=Const
+    const InstArithmetic *ArithInst =
+        llvm::dyn_cast_or_null<const InstArithmetic>(BaseInst);
+    if (ArithInst && (ArithInst->getOp() == InstArithmetic::Add ||
+                      ArithInst->getOp() == InstArithmetic::Sub)) {
+      bool IsAdd = ArithInst->getOp() == InstArithmetic::Add;
+      Variable *Var = NULL;
+      ConstantInteger *Const = NULL;
+      if (Variable *VariableOperand =
+              llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) {
+        Var = VariableOperand;
+        Const = llvm::dyn_cast<ConstantInteger>(ArithInst->getSrc(1));
+      } else if (IsAdd) {
+        Const = llvm::dyn_cast<ConstantInteger>(ArithInst->getSrc(0));
+        Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(1));
+      }
+      if (!(Const && Var)) {
+        break;
+      }
+      Base = Var;
+      Offset += IsAdd ? Const->getValue() : -Const->getValue();
+      continue;
+    }
+
     // Index is Index=Var<<Const && Const+Shift<=3 ==>
     //   Index=Var, Shift+=Const
 
@@ -3398,15 +3425,6 @@
     //   swap(Index,Base)
     // Similar for Base=Const*Var and Base=Var<<Const
 
-    // Base is Base=Var+Const ==>
-    //   set Base=Var, Offset+=Const
-
-    // Base is Base=Const+Var ==>
-    //   set Base=Var, Offset+=Const
-
-    // Base is Base=Var-Const ==>
-    //   set Base=Var, Offset-=Const
-
     // Index is Index=Var+Const ==>
     //   set Index=Var, Offset+=(Const<<Shift)
 
@@ -4039,7 +4057,7 @@
 
 template <> void ConstantInteger::emit(GlobalContext *Ctx) const {
   Ostream &Str = Ctx->getStrEmit();
-  Str << getValue();
+  Str << (int64_t) getValue();
 }
 
 template <> void ConstantFloat::emit(GlobalContext *Ctx) const {
diff --git a/tests_lit/llvm2ice_tests/address-mode-opt.ll b/tests_lit/llvm2ice_tests/address-mode-opt.ll
new file mode 100644
index 0000000..9890c66
--- /dev/null
+++ b/tests_lit/llvm2ice_tests/address-mode-opt.ll
@@ -0,0 +1,64 @@
+; This file checks support for address mode optimization.
+
+; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s
+; RUN: %llvm2ice -O2 --verbose none %s \
+; RUN:               | llvm-mc -arch=x86 -x86-asm-syntax=intel -filetype=obj
+; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
+
+define float @load_arg_plus_200000(float* %arg) {
+entry:
+  %arg.int = ptrtoint float* %arg to i32
+  %addr.int = add i32 %arg.int, 200000
+  %addr.ptr = inttoptr i32 %addr.int to float*
+  %addr.load = load float* %addr.ptr, align 4
+  ret float %addr.load
+; CHECK-LABEL: load_arg_plus_200000:
+; CHECK: movss xmm0, dword ptr [eax+200000]
+}
+
+define float @load_200000_plus_arg(float* %arg) {
+entry:
+  %arg.int = ptrtoint float* %arg to i32
+  %addr.int = add i32 200000, %arg.int
+  %addr.ptr = inttoptr i32 %addr.int to float*
+  %addr.load = load float* %addr.ptr, align 4
+  ret float %addr.load
+; CHECK-LABEL: load_200000_plus_arg:
+; CHECK: movss xmm0, dword ptr [eax+200000]
+}
+
+define float @load_arg_minus_200000(float* %arg) {
+entry:
+  %arg.int = ptrtoint float* %arg to i32
+  %addr.int = sub i32 %arg.int, 200000
+  %addr.ptr = inttoptr i32 %addr.int to float*
+  %addr.load = load float* %addr.ptr, align 4
+  ret float %addr.load
+; CHECK-LABEL: load_arg_minus_200000:
+; CHECK: movss xmm0, dword ptr [eax-200000]
+}
+
+define float @load_200000_minus_arg(float* %arg) {
+entry:
+  %arg.int = ptrtoint float* %arg to i32
+  %addr.int = sub i32 200000, %arg.int
+  %addr.ptr = inttoptr i32 %addr.int to float*
+  %addr.load = load float* %addr.ptr, align 4
+  ret float %addr.load
+; CHECK-LABEL: load_200000_minus_arg:
+; CHECK: movss xmm0, dword ptr [eax]
+}
+
+define float @address_mode_opt_chaining(float* %arg) {
+entry:
+  %arg.int = ptrtoint float* %arg to i32
+  %addr1.int = add i32 12, %arg.int
+  %addr2.int = sub i32 %addr1.int, 4
+  %addr2.ptr = inttoptr i32 %addr2.int to float*
+  %addr2.load = load float* %addr2.ptr, align 4
+  ret float %addr2.load
+; CHECK-LABEL: address_mode_opt_chaining:
+; CHECK: movss xmm0, dword ptr [eax+8]
+}
+
+; ERRORS-NOT: ICE translation error