Implement LSR instructions for the integrated ARM assembler.

Also factors out the body of method lsl() to emitShift(), so
that all forms of shift instructions can use the same code.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1501073002 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index 998c41b..37291e2 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -2603,8 +2603,8 @@
 void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
   mov(rd, Operand(rm, LSL, rs), cond);
 }
-#endif
 
+// Moved to ARM32::AssemblerARM32::lsr()
 void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
                     Condition cond) {
   ASSERT(shift_imm.type() == 1);
@@ -2616,10 +2616,11 @@
   mov(rd, Operand(rm, LSR, shift), cond);
 }
 
-
+// Moved to ARM32::AssemblerARM32::lsr()
 void Assembler::Lsr(Register rd, Register rm, Register rs, Condition cond) {
   mov(rd, Operand(rm, LSR, rs), cond);
 }
+#endif
 
 
 void Assembler::Asr(Register rd, Register rm, const Operand& shift_imm,
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index a2426c0..fe7418f 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -964,10 +964,12 @@
            Condition cond = AL);
   // Moved to ARM32::AssemblerARM32::lsl()
   void Lsl(Register rd, Register rm, Register rs, Condition cond = AL);
-#endif
+  // Moved to ARM32::AssemblerARM32::lsr()
   void Lsr(Register rd, Register rm, const Operand& shift_imm,
            Condition cond = AL);
+  // Moved to ARM32::AssemblerARM32::lsr()
   void Lsr(Register rd, Register rm, Register rs, Condition cond = AL);
+#endif
   void Asr(Register rd, Register rm, const Operand& shift_imm,
            Condition cond = AL);
   void Asr(Register rd, Register rm, Register rs, Condition cond = AL);
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 6611aa0..d06ee7b 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -1122,48 +1122,61 @@
   }
 }
 
+void AssemblerARM32::emitShift(const CondARM32::Cond Cond,
+                               const OperandARM32::ShiftKind Shift,
+                               const Operand *OpRd, const Operand *OpRm,
+                               const Operand *OpSrc1, const bool SetFlags,
+                               const char *InstName) {
+  constexpr IValueT ShiftOpcode = B3 | B2 | B0; // 1101
+  IValueT Rd = encodeRegister(OpRd, "Rd", InstName);
+  IValueT Rm = encodeRegister(OpRm, "Rm", InstName);
+  IValueT Value;
+  switch (encodeOperand(OpSrc1, Value)) {
+  default:
+    llvm::report_fatal_error(std::string(InstName) +
+                             ": Last operand not understood");
+  case EncodedAsShiftImm5: {
+    // XXX (immediate)
+    //   xxx{s}<c> <Rd>, <Rm>, #imm5
+    //
+    // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
+    // iiiii=imm5, and mmmm=Rm.
+    constexpr IValueT Rn = 0; // Rn field is not used.
+    Value = Value | (Rm << kRmShift) | (Shift << kShiftShift);
+    emitType01(Cond, kInstTypeDataRegShift, ShiftOpcode, SetFlags, Rn, Rd,
+               Value, RdIsPcAndSetFlags, InstName);
+    return;
+  }
+  case EncodedAsRegister: {
+    // XXX (register)
+    //   xxx{S}<c> <Rd>, <Rm>, <Rs>
+    //
+    // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
+    // mmmm=Rm, and ssss=Rs.
+    constexpr IValueT Rn = 0; // Rn field is not used.
+    IValueT Rs = encodeRegister(OpSrc1, "Rs", InstName);
+    verifyRegNotPc(Rd, "Rd", InstName);
+    verifyRegNotPc(Rm, "Rm", InstName);
+    verifyRegNotPc(Rs, "Rs", InstName);
+    emitType01(Cond, kInstTypeDataRegShift, ShiftOpcode, SetFlags, Rn, Rd,
+               encodeShiftRotateReg(Rm, Shift, Rs), NoChecks, InstName);
+    return;
+  }
+  }
+}
+
 void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm,
                          const Operand *OpSrc1, bool SetFlags,
                          CondARM32::Cond Cond) {
   constexpr const char *LslName = "lsl";
-  IValueT Rd = encodeRegister(OpRd, "Rd", LslName);
-  IValueT Rm = encodeRegister(OpRm, "Rm", LslName);
-  IValueT Value;
-  switch (encodeOperand(OpSrc1, Value)) {
-  default:
-    llvm::report_fatal_error(std::string(LslName) +
-                             ": Last operand not understood");
-  case EncodedAsShiftImm5: {
-    // LSL (immediate) - ARM section A8.8.94, encoding A1:
-    //   lsl{s}<c> <Rd>, <Rm>, #imm5
-    //
-    // cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
-    // iiiii=imm5, and mmmm=Rm.
-    constexpr IValueT LslOpcode = B3 | B2 | B0; // 1101
-    constexpr IValueT Rn = 0;                   // Rn field is not used.
-    Value = Value | (Rm << kRmShift);
-    emitType01(Cond, kInstTypeDataRegShift, LslOpcode, SetFlags, Rn, Rd, Value,
-               RdIsPcAndSetFlags, LslName);
-    return;
-  }
-  case EncodedAsRegister: {
-    // LSL (register) - ARM section A8.8.95, encoding A1:
-    //   lsl{S}<c> <Rd>, <Rm>, <Rs>
-    //
-    // cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
-    // mmmm=Rm, and ssss=Rs.
-    constexpr IValueT LslOpcode = B3 | B2 | B0; // 1101
-    constexpr IValueT Rn = 0;                   // Rn field is not used.
-    IValueT Rs = encodeRegister(OpSrc1, "Rs", LslName);
-    verifyRegNotPc(Rd, "Rd", LslName);
-    verifyRegNotPc(Rm, "Rm", LslName);
-    verifyRegNotPc(Rs, "Rs", LslName);
-    emitType01(Cond, kInstTypeDataRegShift, LslOpcode, SetFlags, Rn, Rd,
-               encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks,
-               LslName);
-    return;
-  }
-  }
+  emitShift(Cond, OperandARM32::LSL, OpRd, OpRm, OpSrc1, SetFlags, LslName);
+}
+
+void AssemblerARM32::lsr(const Operand *OpRd, const Operand *OpRm,
+                         const Operand *OpSrc1, bool SetFlags,
+                         CondARM32::Cond Cond) {
+  constexpr const char *LsrName = "lsr";
+  emitShift(Cond, OperandARM32::LSR, OpRd, OpRm, OpSrc1, SetFlags, LsrName);
 }
 
 void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 37ea441..705bfe0 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -222,6 +222,9 @@
   void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
            bool SetFlags, CondARM32::Cond Cond);
 
+  void lsr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
+           bool SetFlags, CondARM32::Cond Cond);
+
   void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
 
   void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
@@ -376,6 +379,14 @@
   void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
                  IValueT Rm, IValueT Rs, bool SetFlags, const char *InstName);
 
+  // Pattern cccc0001101s0000ddddxxxxxtt0mmmm where cccc=Cond, s=SetFlags,
+  // dddd=Rd, mmmm=Rm, tt=Shift, and xxxxx is defined by OpSrc1. OpSrc1 defines
+  // either xxxxx=Imm5, or xxxxx=ssss0 where ssss=Rs.
+  void emitShift(const CondARM32::Cond Cond,
+                 const OperandARM32::ShiftKind Shift, const Operand *OpRd,
+                 const Operand *OpRm, const Operand *OpSrc1,
+                 const bool SetFlags, const char *InstName);
+
   // Implements various forms of Unsigned extend value, using pattern
   // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
   // nnnn=Rn, dddd=Rd, rr=Rotation, and mmmm=Rm.
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 6932d2f..2590a10 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -492,6 +492,13 @@
     emitUsingTextFixup(Func);
 }
 
+template <> void InstARM32Lsr::emitIAS(const Cfg *Func) const {
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Asm->lsr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
+  if (Asm->needsTextFixup())
+    emitUsingTextFixup(Func);
+}
+
 template <> void InstARM32Orr::emitIAS(const Cfg *Func) const {
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
diff --git a/tests_lit/assembler/arm32/lsr.ll b/tests_lit/assembler/arm32/lsr.ll
new file mode 100644
index 0000000..f1d1e8a
--- /dev/null
+++ b/tests_lit/assembler/arm32/lsr.ll
@@ -0,0 +1,63 @@
+; Show that we know how to translate lsr.
+
+; NOTE: We use -O2 to get rid of memory stores.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
+; RUN:   | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
+; RUN:   | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -O2 | FileCheck %s --check-prefix=DIS
+
+define internal i32 @LshrAmt(i32 %a) {
+; ASM-LABEL:LshrAmt:
+; DIS-LABEL:00000000 <LshrAmt>:
+; IASM-LABEL:LshrAmt:
+
+entry:
+; ASM-NEXT:.LLshrAmt$entry:
+; IASM-NEXT:.LLshrAmt$entry:
+
+  %v = lshr i32 %a, 23
+
+; ASM-NEXT:     lsr     r0, r0, #23
+; DIS-NEXT:   0:        e1a00ba0
+; IASM-NEXT:    .byte 0xa0
+; IASM-NEXT:    .byte 0xb
+; IASM-NEXT:    .byte 0xa0
+; IASM-NEXT:    .byte 0xe1
+
+  ret i32 %v
+}
+
+define internal i32 @LshrReg(i32 %a, i32 %b) {
+; ASM-LABEL:LshrReg:
+; DIS-LABEL:00000010 <LshrReg>:
+; IASM-LABEL:LshrReg:
+
+entry:
+; ASM-NEXT:.LLshrReg$entry:
+; IASM-NEXT:.LLshrReg$entry:
+
+  %v = lshr i32 %a, %b
+
+; ASM-NEXT:     lsr     r0, r0, r1
+; DIS-NEXT:  10:        e1a00130
+; IASM-NEXT:    .byte 0x30
+; IASM-NEXT:    .byte 0x1
+; IASM-NEXT:    .byte 0xa0
+; IASM-NEXT:    .byte 0xe1
+
+  ret i32 %v
+}