Add MVN (register, immediate) to ARM integrated assembler.

Also removes redundant rule checks in emitType01().

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

Review URL: https://codereview.chromium.org/1460523005 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index e99f70b..b2abcdf 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -92,7 +92,7 @@
   Emit(encoding);
 }
 
-// Moved to ARM32::AssemblerARM32::emitType05.
+// Moved to ARM32::AssemblerARM32::emitType05()
 void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
   ASSERT(cond != kNoCondition);
   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -304,26 +304,26 @@
 
 
 #if 0
-// Moved to ARM32::AssemblerARM32::bic();
+// Moved to ARM32::AssemblerARM32::bic()
 void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) {
   EmitType01(cond, o.type(), BIC, 0, rn, rd, o);
 }
 
-// Moved to ARM32::AssemblerARM32::bic();
+// Moved to ARM32::AssemblerARM32::bic()
 void Assembler::bics(Register rd, Register rn, Operand o, Condition cond) {
   EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
 }
-#endif
 
+// Moved to ARM32::AssemblerARM32::mvn()
 void Assembler::mvn(Register rd, Operand o, Condition cond) {
   EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
 }
 
-
+// Moved to ARM32::AssemblerARM32::mvn()
 void Assembler::mvns(Register rd, Operand o, Condition cond) {
   EmitType01(cond, o.type(), MVN, 1, R0, rd, o);
 }
-
+#endif
 
 void Assembler::clz(Register rd, Register rm, Condition cond) {
   ASSERT(rd != kNoRegister);
@@ -340,7 +340,7 @@
 
 
 #if
-// Moved to ARM32::AssemblerARM32::movw
+// Moved to ARM32::AssemblerARM32::movw()
 void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
   ASSERT(cond != kNoCondition);
   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -350,7 +350,7 @@
 }
 
 
-// Moved to ARM32::AssemblerARM32::movt
+// Moved to ARM32::AssemblerARM32::movt()
 void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
   ASSERT(cond != kNoCondition);
   int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -361,7 +361,7 @@
 #endif
 
 #if 0
-// Moved to ARM32::AssemblerARM32::emitMulOp
+// Moved to ARM32::AssemblerARM32::emitMulOp()
 void Assembler::EmitMulOp(Condition cond, int32_t opcode,
                           Register rd, Register rn,
                           Register rm, Register rs) {
@@ -380,7 +380,7 @@
   Emit(encoding);
 }
 
-// Moved to ARM32::AssemblerARM32::mul
+// Moved to ARM32::AssemblerARM32::mul()
 void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
   // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
   EmitMulOp(cond, 0, R0, rd, rn, rm);
@@ -2104,7 +2104,7 @@
 }
 
 #if 0
-// Moved to ::canEncodeBranchoffset in IceAssemblerARM32.cpp.
+// Moved to ::canEncodeBranchoffset() in IceAssemblerARM32.cpp.
 static bool CanEncodeBranchOffset(int32_t offset) {
   ASSERT(Utils::IsAligned(offset, 4));
   // Note: This check doesn't take advantage of the fact that offset>>2
@@ -2112,7 +2112,7 @@
   return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
 }
 
-// Moved to ARM32::AssemblerARM32::encodeBranchOffset.
+// Moved to ARM32::AssemblerARM32::encodeBranchOffset()
 int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
   // The offset is off by 8 due to the way the ARM CPUs read PC.
   offset -= Instr::kPCReadOffset;
@@ -2129,7 +2129,7 @@
   return (inst & ~kBranchOffsetMask) | offset;
 }
 
-// Moved to AssemberARM32::decodeBranchOffset.
+// Moved to AssemberARM32::decodeBranchOffset()
 int Assembler::DecodeBranchOffset(int32_t inst) {
   // Sign-extend, left-shift by 2, then add 8.
   return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 688104b..de7d50e 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -507,10 +507,11 @@
   // Moved to ARM32::IceAssemblerARM32::bic()
   void bic(Register rd, Register rn, Operand o, Condition cond = AL);
   void bics(Register rd, Register rn, Operand o, Condition cond = AL);
-#endif
 
+  // Moved to ARM32::IceAssemblerARM32::mvn()
   void mvn(Register rd, Operand o, Condition cond = AL);
   void mvns(Register rd, Operand o, Condition cond = AL);
+#endif
 
   // Miscellaneous data-processing instructions.
   void clz(Register rd, Register rm, Condition cond = AL);
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 08ec155..cd4735b 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -187,16 +187,17 @@
   // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
   // value.
   DecodedAsRotatedImm8,
-  // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
+  // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
   // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
   // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
   DecodedAsImmRegOffset,
-  // i.e. 0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
+  // Value=0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
   // mmmm is the index register Rm, iiiii is the shift amount, ss is the shift
   // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
   // writeback to Rn.
   DecodedAsShiftRotateImm5,
-  // i.e. 000000000000000000000iiiii0000000 iiii defines Imm5 value to shift.
+  // Value=000000000000000000000iiiii0000000 iiii defines the Imm5 value to
+  // shift.
   DecodedAsShiftImm5,
   // Value is 32bit integer constant.
   DecodedAsConstI32
@@ -218,8 +219,8 @@
   return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
 }
 
-// Encodes mmmmtt01ssss for data-processing (2nd) operands where mmmm=Rm,
-// ssss=Rs, and tt=Shift.
+// Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and
+// tt=Shift.
 IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
                              IValueT Rs) {
   return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 |
@@ -481,15 +482,6 @@
 void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
                                 const Operand *OpSrc1, bool SetFlags,
                                 CondARM32::Cond Cond, EmitChecks RuleChecks) {
-  switch (RuleChecks) {
-  case NoChecks:
-    break;
-  case RdIsPcAndSetFlags:
-    if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
-      // Conditions of rule violated.
-      return setNeedsTextFixup();
-    break;
-  }
 
   IValueT Src1Value;
   // TODO(kschimpf) Other possible decodings of data operations.
@@ -564,8 +556,9 @@
   // XXX (register)
   //   XXX<c> <Rn>, <Rm>{, <shift>}
   //
-  // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm,
-  // iiiii=Shift, tt=ShiftKind, yyy=kInstTypeDataRegister, and xxxx=Opcode.
+  // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm, iiiii
+  // defines shift constant, tt=ShiftKind, yyy=kInstTypeDataRegister, and
+  // xxxx=Opcode.
   //
   // XXX (immediate)
   //  XXX<c> <Rn>, #<RotatedImm8>
@@ -1047,6 +1040,28 @@
   emitInst(Encoding);
 }
 
+void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc,
+                         CondARM32::Cond Cond) {
+  // MVN (immediate) - ARM section A8.8.115, encoding A1:
+  //   mvn{s}<c> <Rd>, #<const>
+  //
+  // cccc0011111s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags=0, dddd=Rd,
+  // and iiiiiiiiiiii=const
+  //
+  // MVN (register) - ARM section A8.8.116, encoding A1:
+  //   mvn{s}<c> <Rd>, <Rm>{, <shift>
+  //
+  // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd,
+  // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind.
+  IValueT Rd;
+  if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
+    return setNeedsTextFixup();
+  constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111
+  constexpr IValueT Rn = 0;
+  constexpr bool SetFlags = false;
+  emitType01(MvnOpcode, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags);
+}
+
 void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
                          const Operand *OpSrc1, bool SetFlags,
                          CondARM32::Cond Cond) {
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 4372085..59383fb 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -238,6 +238,8 @@
   void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
            bool SetFlags, CondARM32::Cond Cond);
 
+  void mvn(const Operand *OpRd, const Operand *OpScc, CondARM32::Cond Cond);
+
   void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
            bool SetFlags, CondARM32::Cond Cond);
 
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 0ca2d6a..24a9e0b 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1158,6 +1158,14 @@
     emitUsingTextFixup(Func);
 }
 
+template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Asm->mvn(getDest(), getSrc(0), getPredicate());
+  if (Asm->needsTextFixup())
+    emitUsingTextFixup(Func);
+}
+
 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
   assert(getSrcSize() == 1);
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
diff --git a/tests_lit/assembler/arm32/mvn.ll b/tests_lit/assembler/arm32/mvn.ll
new file mode 100644
index 0000000..f23d218
--- /dev/null
+++ b/tests_lit/assembler/arm32/mvn.ll
@@ -0,0 +1,145 @@
+; Tests MVN instruction.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN:   | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -Om1 | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; RUN:   | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -Om1 | FileCheck %s --check-prefix=DIS
+
+define internal void @mvmEx(i32 %a, i32 %b) {
+; ASM-LABEL:mvmEx:
+; DIS-LABEL:00000000 <mvmEx>:
+; IASM-LABEL:mvmEx:
+
+entry:
+; ASM-NEXT:.LmvmEx$entry:
+; IASM-NEXT:.LmvmEx$entry:
+
+; ASM-NEXT:     sub     sp, sp, #24
+; DIS-NEXT:   0:        e24dd018
+; IASM-NEXT:    .byte 0x18
+; IASM-NEXT:    .byte 0xd0
+; IASM-NEXT:    .byte 0x4d
+; IASM-NEXT:    .byte 0xe2
+
+; ASM-NEXT:     str     r0, [sp, #20]
+; ASM-NEXT:     # [sp, #20] = def.pseudo 
+; DIS-NEXT:   4:        e58d0014
+; IASM-NEXT:    .byte 0x14
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x8d
+; IASM-NEXT:    .byte 0xe5
+
+; ASM-NEXT:     str     r1, [sp, #16]
+; ASM-NEXT:     # [sp, #16] = def.pseudo 
+; DIS-NEXT:   8:        e58d1010
+; IASM-NEXT:    .byte 0x10
+; IASM-NEXT:    .byte 0x10
+; IASM-NEXT:    .byte 0x8d
+; IASM-NEXT:    .byte 0xe5
+
+  %b.arg_trunc = trunc i32 %b to i1
+
+; ASM-NEXT:     ldr     r0, [sp, #16]
+; DIS-NEXT:   c:        e59d0010
+; IASM-NEXT:    .byte 0x10
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x9d
+; IASM-NEXT:    .byte 0xe5
+
+; ASM-NEXT:     and     r0, r0, #1
+; DIS-NEXT:  10:        e2000001
+; IASM-NEXT:    .byte 0x1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0xe2
+
+; ASM-NEXT:     strb    r0, [sp, #12]
+; ASM-NEXT:     # [sp, #12] = def.pseudo 
+; DIS-NEXT:  14:        e5cd000c
+; IASM-NEXT:    strb    r0, [sp, #12]
+
+  %a.arg_trunc = trunc i32 %a to i1
+
+; ASM-NEXT:     ldr     r0, [sp, #20]
+; DIS-NEXT:  18:        e59d0014
+; IASM-NEXT:    .byte 0x14
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x9d
+; IASM-NEXT:    .byte 0xe5
+
+; ASM-NEXT:     and     r0, r0, #1
+; DIS-NEXT:  1c:        e2000001
+; IASM-NEXT:    .byte 0x1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0xe2
+
+; ASM-NEXT:     strb    r0, [sp, #8]
+; ASM-NEXT:     # [sp, #8] = def.pseudo 
+; DIS-NEXT:  20:        e5cd0008
+; IASM-NEXT:    strb    r0, [sp, #8]
+
+  %conv = zext i1 %a.arg_trunc to i32
+
+; ASM-NEXT:     ldrb    r0, [sp, #8]
+; DIS-NEXT:  24:        e5dd0008
+; IASM-NEXT:    ldrb    r0, [sp, #8]
+
+; ASM-NEXT:     str     r0, [sp, #4]
+; ASM-NEXT:     # [sp, #4] = def.pseudo 
+; DIS-NEXT:  28:        e58d0004
+; IASM-NEXT:    .byte 0x4
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x8d
+; IASM-NEXT:    .byte 0xe5
+
+  %ignore = sext i1 %b.arg_trunc to i32
+
+; ASM-NEXT:     mov     r0, #0
+; DIS-NEXT:  2c:        e3a00000
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0xa0
+; IASM-NEXT:    .byte 0xe3
+
+; ASM-NEXT:     ldrb    r1, [sp, #12]
+; DIS-NEXT:  30:        e5dd100c
+; IASM-NEXT:    ldrb    r1, [sp, #12]
+
+; ASM-NEXT:     tst     r1, #1
+; DIS-NEXT:  34:        e3110001
+; IASM-NEXT:    .byte 0x1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x11
+; IASM-NEXT:    .byte 0xe3
+
+; ********* Use of MVN ********
+; ASM-NEXT:     mvn     r1, #0
+; DIS-NEXT:  38:        e3e01000
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x10
+; IASM-NEXT:    .byte 0xe0
+; IASM-NEXT:    .byte 0xe3
+
+; ASM-NEXT:     movne   r0, r1
+; DIS-NEXT:  3c:        11a00001
+; IASM-NEXT:    .byte 0x1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0xa0
+; IASM-NEXT:    .byte 0x11
+
+  ret void
+}