Subzero, MIPS32: Implement logical instructions ashr, lshr, shl

This patch adds support for logical operations ashr, lshr and shl.

R=stichnot@chromium.org

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

Patch from Srdjan Obucina <Srdjan.Obucina@imgtec.com>.
diff --git a/src/IceInstMIPS32.cpp b/src/IceInstMIPS32.cpp
index 30d48e3..043c2ca 100644
--- a/src/IceInstMIPS32.cpp
+++ b/src/IceInstMIPS32.cpp
@@ -67,11 +67,15 @@
 template <> const char *InstMIPS32Or::Opcode = "or";
 template <> const char *InstMIPS32Ori::Opcode = "ori";
 template <> const char *InstMIPS32Sll::Opcode = "sll";
+template <> const char *InstMIPS32Sllv::Opcode = "sllv";
 template <> const char *InstMIPS32Slt::Opcode = "slt";
 template <> const char *InstMIPS32Slti::Opcode = "slti";
 template <> const char *InstMIPS32Sltiu::Opcode = "sltiu";
 template <> const char *InstMIPS32Sltu::Opcode = "sltu";
 template <> const char *InstMIPS32Sra::Opcode = "sra";
+template <> const char *InstMIPS32Srav::Opcode = "srav";
+template <> const char *InstMIPS32Srl::Opcode = "srl";
+template <> const char *InstMIPS32Srlv::Opcode = "srlv";
 template <> const char *InstMIPS32Sub::Opcode = "sub";
 template <> const char *InstMIPS32Subu::Opcode = "subu";
 template <> const char *InstMIPS32Xor::Opcode = "xor";
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
index 4247e7e..85f268e 100644
--- a/src/IceInstMIPS32.h
+++ b/src/IceInstMIPS32.h
@@ -139,11 +139,15 @@
     Ori,
     Ret,
     Sll,
+    Sllv,
     Slt,
     Slti,
     Sltiu,
     Sltu,
     Sra,
+    Srav,
+    Srl,
+    Srlv,
     Sub,
     Subu,
     Xor,
@@ -478,11 +482,15 @@
 using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
 using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
 using InstMIPS32Sll = InstMIPS32Imm16<InstMIPS32::Sll>;
+using InstMIPS32Sllv = InstMIPS32ThreeAddrGPR<InstMIPS32::Sllv>;
 using InstMIPS32Slt = InstMIPS32ThreeAddrGPR<InstMIPS32::Slt>;
 using InstMIPS32Slti = InstMIPS32Imm16<InstMIPS32::Slti>;
 using InstMIPS32Sltiu = InstMIPS32Imm16<InstMIPS32::Sltiu>;
 using InstMIPS32Sltu = InstMIPS32ThreeAddrGPR<InstMIPS32::Sltu>;
 using InstMIPS32Sra = InstMIPS32Imm16<InstMIPS32::Sra>;
+using InstMIPS32Srav = InstMIPS32ThreeAddrGPR<InstMIPS32::Srav>;
+using InstMIPS32Srl = InstMIPS32Imm16<InstMIPS32::Srl>;
+using InstMIPS32Srlv = InstMIPS32ThreeAddrGPR<InstMIPS32::Srlv>;
 using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>;
 using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>;
 using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 79f02fb..a2e82b2 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -692,9 +692,6 @@
   switch (Instr->getOp()) {
   default:
     break;
-  case InstArithmetic::Shl:
-  case InstArithmetic::Lshr:
-  case InstArithmetic::Ashr:
   case InstArithmetic::Udiv:
   case InstArithmetic::Sdiv:
   case InstArithmetic::Urem:
@@ -742,12 +739,21 @@
     _mov(Dest, T);
     return;
   }
-  case InstArithmetic::Shl:
-    break;
-  case InstArithmetic::Lshr:
-    break;
-  case InstArithmetic::Ashr:
-    break;
+  case InstArithmetic::Shl: {
+    _sllv(T, Src0R, Src1R);
+    _mov(Dest, T);
+    return;
+  }
+  case InstArithmetic::Lshr: {
+    _srlv(T, Src0R, Src1R);
+    _mov(Dest, T);
+    return;
+  }
+  case InstArithmetic::Ashr: {
+    _srav(T, Src0R, Src1R);
+    _mov(Dest, T);
+    return;
+  }
   case InstArithmetic::Udiv:
     break;
   case InstArithmetic::Sdiv:
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 0454f30..a90311a 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -224,6 +224,10 @@
     Context.insert<InstMIPS32Sll>(Dest, Src, Imm);
   }
 
+  void _sllv(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Sllv>(Dest, Src0, Src1);
+  }
+
   void _slt(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32Slt>(Dest, Src0, Src1);
   }
@@ -244,6 +248,18 @@
     Context.insert<InstMIPS32Sra>(Dest, Src, Imm);
   }
 
+  void _srav(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Srav>(Dest, Src0, Src1);
+  }
+
+  void _srl(Variable *Dest, Variable *Src, uint32_t Imm) {
+    Context.insert<InstMIPS32Srl>(Dest, Src, Imm);
+  }
+
+  void _srlv(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Srlv>(Dest, Src0, Src1);
+  }
+
   void _sub(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32Sub>(Dest, Src0, Src1);
   }
diff --git a/tests_lit/llvm2ice_tests/shift.ll b/tests_lit/llvm2ice_tests/shift.ll
index 020b1c9..2478544 100644
--- a/tests_lit/llvm2ice_tests/shift.ll
+++ b/tests_lit/llvm2ice_tests/shift.ll
@@ -24,6 +24,17 @@
 ; RUN:   | %if --need=target_ARM32 --need=allow_dump \
 ; RUN:   --command FileCheck --check-prefix ARM32 %s
 
+; RUN: %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target mips32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix MIPS32 %s
+
+; RUN: %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target mips32 -i %s --args -Om1 --skip-unimplemented \
+; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix MIPS32 %s
 
 @i1 = internal global [4 x i8] zeroinitializer, align 4
 @i2 = internal global [4 x i8] zeroinitializer, align 4
@@ -73,6 +84,9 @@
 ; CHECK-LABEL: shlImmLarge
 ; CHECK: shl {{.*}},0x1
 
+; MIPS32-LABEL: shlImmLarge
+; MIPS32: sllv
+
 define internal i32 @shlImmNeg(i32 %val) {
 entry:
   %result = shl i32 %val, -1
@@ -81,6 +95,9 @@
 ; CHECK-LABEL: shlImmNeg
 ; CHECK: shl {{.*}},0xff
 
+; MIPS32-LABEL: shlImmNeg
+; MIPS32: sllv
+
 define internal i32 @lshrImmLarge(i32 %val) {
 entry:
   %result = lshr i32 %val, 257
@@ -89,6 +106,9 @@
 ; CHECK-LABEL: lshrImmLarge
 ; CHECK: shr {{.*}},0x1
 
+; MIPS32-LABEL: lshrImmLarge
+; MIPS32: srlv
+
 define internal i32 @lshrImmNeg(i32 %val) {
 entry:
   %result = lshr i32 %val, -1
@@ -97,6 +117,9 @@
 ; CHECK-LABEL: lshrImmNeg
 ; CHECK: shr {{.*}},0xff
 
+; MIPS32-LABEL: lshrImmNeg
+; MIPS32: srlv
+
 define internal i32 @ashrImmLarge(i32 %val) {
 entry:
   %result = ashr i32 %val, 257
@@ -105,6 +128,9 @@
 ; CHECK-LABEL: ashrImmLarge
 ; CHECK: sar {{.*}},0x1
 
+; MIPS32-LABEL: ashrImmLarge
+; MIPS32: srav
+
 define internal i32 @ashrImmNeg(i32 %val) {
 entry:
   %result = ashr i32 %val, -1
@@ -113,6 +139,9 @@
 ; CHECK-LABEL: ashrImmNeg
 ; CHECK: sar {{.*}},0xff
 
+; MIPS32-LABEL: ashrImmNeg
+; MIPS32: srav
+
 define internal i64 @shlImm64One(i64 %val) {
 entry:
   %result = shl i64 %val, 1