[SubZero] Legalize load, store for MIPS post lower

This patch legalizes load, store instructions post lowering.

R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/2411193003 .

Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 331f1ed..7f501ef 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -1529,7 +1529,17 @@
         Target->Ctx->getConstantInt32(-Offset), ScratchRegNum);
     Target->_sub(ScratchReg, Base, OffsetVal);
   } else {
-    Target->_addiu(ScratchReg, Base, Offset);
+    constexpr bool SignExt = true;
+    if (!OperandMIPS32Mem::canHoldOffset(Base->getType(), SignExt, Offset)) {
+      const uint32_t UpperBits = (Offset >> 16) & 0xFFFF;
+      const uint32_t LowerBits = Offset & 0xFFFF;
+      Target->_lui(ScratchReg, Target->Ctx->getConstantInt32(UpperBits));
+      if (LowerBits)
+        Target->_ori(ScratchReg, ScratchReg, LowerBits);
+      Target->_addu(ScratchReg, ScratchReg, Base);
+    } else {
+      Target->_addiu(ScratchReg, Base, Offset);
+    }
   }
 
   return ScratchReg;
@@ -1731,6 +1741,35 @@
   }
 }
 
+OperandMIPS32Mem *
+TargetMIPS32::PostLoweringLegalizer::legalizeMemOperand(OperandMIPS32Mem *Mem) {
+  if (llvm::isa<ConstantRelocatable>(Mem->getOffset())) {
+    return nullptr;
+  }
+  Variable *Base = Mem->getBase();
+  auto *Ci32 = llvm::cast<ConstantInteger32>(Mem->getOffset());
+  int32_t Offset = Ci32->getValue();
+
+  if (Base->isRematerializable()) {
+    const int32_t ExtraOffset =
+        (Base->getRegNum() == Target->getFrameOrStackReg())
+            ? Target->getFrameFixedAllocaOffset()
+            : 0;
+    Offset += Base->getStackOffset() + ExtraOffset;
+    Base = Target->getPhysicalRegister(Base->getRegNum());
+  }
+
+  constexpr bool SignExt = true;
+  if (!OperandMIPS32Mem::canHoldOffset(Mem->getType(), SignExt, Offset)) {
+    Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
+    Offset = 0;
+  }
+
+  return OperandMIPS32Mem::create(
+      Target->Func, Mem->getType(), Base,
+      llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)));
+}
+
 void TargetMIPS32::postLowerLegalization() {
   Func->dump("Before postLowerLegalization");
   assert(hasComputedFrame());
@@ -1740,11 +1779,58 @@
     while (!Context.atEnd()) {
       PostIncrLoweringContext PostIncrement(Context);
       Inst *CurInstr = iteratorToInst(Context.getCur());
-
-      // TODO(sagar.thakur): Add remaining cases of legalization.
-
+      const SizeT NumSrcs = CurInstr->getSrcSize();
+      Operand *Src0 = NumSrcs < 1 ? nullptr : CurInstr->getSrc(0);
+      Operand *Src1 = NumSrcs < 2 ? nullptr : CurInstr->getSrc(1);
+      auto *Src0V = llvm::dyn_cast_or_null<Variable>(Src0);
+      auto *Src0M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src0);
+      auto *Src1M = llvm::dyn_cast_or_null<OperandMIPS32Mem>(Src1);
+      Variable *Dst = CurInstr->getDest();
       if (auto *MovInstr = llvm::dyn_cast<InstMIPS32Mov>(CurInstr)) {
         Legalizer.legalizeMov(MovInstr);
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Sw>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
+          _sw(Src0V, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Swc1>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
+          _swc1(Src0V, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Sdc1>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src1M)) {
+          _sdc1(Src0V, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Lw>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
+          _lw(Dst, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Lwc1>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
+          _lwc1(Dst, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
+      }
+      if (llvm::isa<InstMIPS32Ldc1>(CurInstr)) {
+        if (auto *LegalMem = Legalizer.legalizeMemOperand(Src0M)) {
+          _ldc1(Dst, LegalMem);
+          CurInstr->setDeleted();
+        }
+        continue;
       }
     }
   }
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 842f266..01f68ca 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -90,6 +90,7 @@
   RegNumT getFrameOrStackReg() const override {
     return UsesFramePointer ? getFrameReg() : getStackReg();
   }
+  RegNumT getReservedTmpReg() const { return RegMIPS32::Reg_AT; }
   size_t typeWidthInBytesOnStack(Type Ty) const override {
     // Round up to the next multiple of 4 bytes. In particular, i1, i8, and i16
     // are rounded up to 4 bytes.
@@ -726,6 +727,10 @@
         : Target(Target), StackOrFrameReg(Target->getPhysicalRegister(
                               Target->getFrameOrStackReg())) {}
 
+    /// Legalizes Mem. if Mem.Base is a rematerializable variable,
+    /// Mem.Offset is fixed up.
+    OperandMIPS32Mem *legalizeMemOperand(OperandMIPS32Mem *Mem);
+
     /// Legalizes Mov if its Source (or Destination) is a spilled Variable, or
     /// if its Source is a Rematerializable variable (this form is used in lieu
     /// of lea, which is not available in MIPS.)
diff --git a/tests_lit/llvm2ice_tests/mips-legalization.ll b/tests_lit/llvm2ice_tests/mips-legalization.ll
new file mode 100644
index 0000000..cc9414d
--- /dev/null
+++ b/tests_lit/llvm2ice_tests/mips-legalization.ll
@@ -0,0 +1,84 @@
+; This file checks support for legalization in MIPS.
+
+; REQUIRES: allow_dump
+
+; RUN: %if --need=target_MIPS32 \
+; RUN:   --command %p2i --filetype=asm --assemble --disassemble \
+; RUN:   --target mips32 -i %s --args -O2 \
+; RUN:   | %if --need=target_MIPS32 \
+; RUN:     --command FileCheck --check-prefix MIPS32 %s
+
+define internal i32 @legalization(i32 %a, i32 %b, i32 %c, i32 %d,
+                                  i32 %e, i32 %f) {
+entry:
+  %a.addr = alloca i8, i32 4, align 4
+  %b.addr = alloca i8, i32 4, align 4
+  %c.addr = alloca i8, i32 4, align 4
+  %d.addr = alloca i8, i32 4, align 4
+  %e.addr = alloca i8, i32 4, align 4
+  %f.addr = alloca i8, i32 4, align 4
+  %r1 = alloca i8, i32 4, align 4
+  %r2 = alloca i8, i32 4, align 4
+  %r3 = alloca i8, i32 4, align 4
+  %a.addr.bc = bitcast i8* %a.addr to i32*
+  store i32 %a, i32* %a.addr.bc, align 1
+  %b.addr.bc = bitcast i8* %b.addr to i32*
+  store i32 %b, i32* %b.addr.bc, align 1
+  %c.addr.bc = bitcast i8* %c.addr to i32*
+  store i32 %c, i32* %c.addr.bc, align 1
+  %d.addr.bc = bitcast i8* %d.addr to i32*
+  store i32 %d, i32* %d.addr.bc, align 1
+  %e.addr.bc = bitcast i8* %e.addr to i32*
+  store i32 %e, i32* %e.addr.bc, align 1
+  %f.addr.bc = bitcast i8* %f.addr to i32*
+  store i32 %f, i32* %f.addr.bc, align 1
+  %a.addr.bc1 = bitcast i8* %a.addr to i32*
+  %0 = load i32, i32* %a.addr.bc1, align 1
+  %f.addr.bc2 = bitcast i8* %f.addr to i32*
+  %1 = load i32, i32* %f.addr.bc2, align 1
+  %add = add i32 %0, %1
+  %r1.bc = bitcast i8* %r1 to i32*
+  store i32 %add, i32* %r1.bc, align 1
+  %b.addr.bc3 = bitcast i8* %b.addr to i32*
+  %2 = load i32, i32* %b.addr.bc3, align 1
+  %e.addr.bc4 = bitcast i8* %e.addr to i32*
+  %3 = load i32, i32* %e.addr.bc4, align 1
+  %add1 = add i32 %2, %3
+  %r2.bc = bitcast i8* %r2 to i32*
+  store i32 %add1, i32* %r2.bc, align 1
+  %r1.bc5 = bitcast i8* %r1 to i32*
+  %4 = load i32, i32* %r1.bc5, align 1
+  %r2.bc6 = bitcast i8* %r2 to i32*
+  %5 = load i32, i32* %r2.bc6, align 1
+  %add2 = add i32 %4, %5
+  %r3.bc = bitcast i8* %r3 to i32*
+  store i32 %add2, i32* %r3.bc, align 1
+  %r3.bc7 = bitcast i8* %r3 to i32*
+  %6 = load i32, i32* %r3.bc7, align 1
+  ret i32 %6
+}
+; MIPS32-LABEL: legalization
+; MIPS32: addiu sp,sp,-48
+; MIPS32: lw [[ARG_E:.*]],64(sp)
+; MIPS32: lw [[ARG_F:.*]],68(sp)
+; MIPS32: sw a0,0(sp)
+; MIPS32: sw a1,4(sp)
+; MIPS32: sw a2,8(sp)
+; MIPS32: sw a3,12(sp)
+; MIPS32: sw [[ARG_E]],16(sp)
+; MIPS32: sw [[ARG_F]],20(sp)
+; MIPS32: lw [[TMP_A:.*]],0(sp)
+; MIPS32: lw [[TMP_F:.*]],20(sp)
+; MIPS32: addu [[ADD1:.*]],[[TMP_A]],[[TMP_F]]
+; MIPS32: sw [[ADD1]],24(sp)
+; MIPS32: lw [[TMP_B:.*]],4(sp)
+; MIPS32: lw [[TMP_E:.*]],16(sp)
+; MIPS32: addu [[ADD2:.*]],[[TMP_B]],[[TMP_E]]
+; MIPS32: sw [[ADD2]],28(sp)
+; MIPS32: lw [[TMP_ADD1:.*]],24(sp)
+; MIPS32: lw [[TMP_ADD2:.*]],28(sp)
+; MIPS32: addu [[ADD3:.*]],[[TMP_ADD1]],[[TMP_ADD2]]
+; MIPS32: sw [[ADD3]],32(sp)
+; MIPS32: lw v0,32(sp)
+; MIPS32: addiu sp,sp,48
+; MIPS32: jr ra