Revision: 4913
Author: [email protected]
Date: Tue Jun 22 01:38:32 2010
Log: Add movw and movt support for ARMv7.  This includes some code from
Zhang Kun.  For now we only emit movw and movt in places where no
relocation is needed.  Small performance boost (around 0.5%).
Also adds support for turning ALU operations (eor etc.) with
large immediates into mvn or movw followed by a register-based
ALU operation.
Review URL: http://codereview.chromium.org/2821014
http://code.google.com/p/v8/source/detail?r=4913

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/constants-arm.h
 /branches/bleeding_edge/src/arm/disasm-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/jsregexp.cc
 /branches/bleeding_edge/test/cctest/test-disasm-arm.cc

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Mon Jun 14 04:20:36 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Tue Jun 22 01:38:32 2010
@@ -282,6 +282,11 @@
 const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
 const Instr kMovMvnPattern = 0xd * B21;
 const Instr kMovMvnFlip = B22;
+const Instr kMovLeaveCCMask = 0xdff * B16;
+const Instr kMovLeaveCCPattern = 0x1a0 * B16;
+const Instr kMovwMask = 0xff * B20;
+const Instr kMovwPattern = 0x30 * B20;
+const Instr kMovwLeaveCCFlip = 0x5 * B21;
 const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
 const Instr kCmpCmnPattern = 0x15 * B20;
 const Instr kCmpCmnFlip = B21;
@@ -638,6 +643,12 @@
     L->Unuse();
   }
 }
+
+
+static Instr EncodeMovwImmediate(uint32_t immediate) {
+  ASSERT(immediate < 0x10000);
+  return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
+}


 // Low-level code emission routines depending on the addressing mode.
@@ -664,6 +675,15 @@
       if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
         *instr ^= kMovMvnFlip;
         return true;
+      } else if ((*instr & kMovLeaveCCMask) == kMovLeaveCCPattern) {
+        if (CpuFeatures::IsSupported(ARMv7)) {
+          if (imm32 < 0x10000) {
+            *instr ^= kMovwLeaveCCFlip;
+            *instr |= EncodeMovwImmediate(imm32);
+            *rotate_imm = *immed_8 = 0;  // Not used for movw.
+            return true;
+          }
+        }
       }
     } else if ((*instr & kCmpCmnMask) == kCmpCmnPattern) {
       if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
@@ -695,7 +715,7 @@
// if they can be encoded in the ARM's 12 bits of immediate-offset instruction // space. There is no guarantee that the relocated location can be similarly
 // encoded.
-static bool MustUseIp(RelocInfo::Mode rmode) {
+static bool MustUseConstantPool(RelocInfo::Mode rmode) {
   if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
 #ifdef DEBUG
     if (!Serializer::enabled()) {
@@ -712,7 +732,7 @@

 bool Operand::is_single_instruction() const {
   if (rm_.is_valid()) return true;
-  if (MustUseIp(rmode_)) return false;
+  if (MustUseConstantPool(rmode_)) return false;
   uint32_t dummy1, dummy2;
   return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
 }
@@ -728,19 +748,34 @@
     // Immediate.
     uint32_t rotate_imm;
     uint32_t immed_8;
-    if (MustUseIp(x.rmode_) ||
+    if (MustUseConstantPool(x.rmode_) ||
         !fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
// The immediate operand cannot be encoded as a shifter operand, so load // it first to register ip and change the original instruction to use ip. // However, if the original instruction is a 'mov rd, x' (not setting the
       // condition code), then replace it with a 'ldr rd, [pc]'.
-      RecordRelocInfo(x.rmode_, x.imm32_);
       CHECK(!rn.is(ip));  // rn should never be ip, or will be trashed
       Condition cond = static_cast<Condition>(instr & CondMask);
       if ((instr & ~CondMask) == 13*B21) {  // mov, S not set
-        ldr(rd, MemOperand(pc, 0), cond);
+        if (MustUseConstantPool(x.rmode_) ||
+            !CpuFeatures::IsSupported(ARMv7)) {
+          RecordRelocInfo(x.rmode_, x.imm32_);
+          ldr(rd, MemOperand(pc, 0), cond);
+        } else {
+          // Will probably use movw, will certainly not use constant pool.
+          mov(rd, Operand(x.imm32_ & 0xffff), LeaveCC, cond);
+          movt(rd, static_cast<uint32_t>(x.imm32_) >> 16, cond);
+        }
       } else {
-        ldr(ip, MemOperand(pc, 0), cond);
+ // If this is not a mov or mvn instruction we may still be able to avoid
+        // a constant pool entry by using mvn or movw.
+        if (!MustUseConstantPool(x.rmode_) &&
+            (instr & kMovMvnMask) != kMovMvnPattern) {
+          mov(ip, x, LeaveCC, cond);
+        } else {
+          RecordRelocInfo(x.rmode_, x.imm32_);
+          ldr(ip, MemOperand(pc, 0), cond);
+        }
         addrmod1(instr, rn, rd, Operand(ip));
       }
       return;
@@ -1049,6 +1084,17 @@
ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
   addrmod1(cond | 13*B21 | s, r0, dst, src);
 }
+
+
+void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
+  ASSERT(immediate < 0x10000);
+  mov(reg, Operand(immediate), LeaveCC, cond);
+}
+
+
+void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
+  emit(cond | 0x34*B20 | reg.code()*B12 | EncodeMovwImmediate(immediate));
+}


 void Assembler::bic(Register dst, Register src1, const Operand& src2,
@@ -1231,7 +1277,7 @@
     // Immediate.
     uint32_t rotate_imm;
     uint32_t immed_8;
-    if (MustUseIp(src.rmode_) ||
+    if (MustUseConstantPool(src.rmode_) ||
         !fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
       // Immediate operand cannot be encoded, load it first to register ip.
       RecordRelocInfo(src.rmode_, src.imm32_);
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Thu Jun 17 01:41:48 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Tue Jun 22 01:38:32 2010
@@ -548,6 +548,12 @@
 extern const Instr kMovMvnPattern;
 extern const Instr kMovMvnFlip;

+extern const Instr kMovLeaveCCMask;
+extern const Instr kMovLeaveCCPattern;
+extern const Instr kMovwMask;
+extern const Instr kMovwPattern;
+extern const Instr kMovwLeaveCCFlip;
+
 extern const Instr kCmpCmnMask;
 extern const Instr kCmpCmnPattern;
 extern const Instr kCmpCmnFlip;
@@ -774,6 +780,13 @@
void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
     mov(dst, Operand(src), s, cond);
   }
+
+  // ARMv7 instructions for loading a 32 bit immediate in two instructions.
+  // This may actually emit a different mov instruction, but on an ARMv7 it
+  // is guaranteed to only emit one instruction.
+  void movw(Register reg, uint32_t immediate, Condition cond = al);
+  // The constant for movt should be in the range 0-0xffff.
+  void movt(Register reg, uint32_t immediate, Condition cond = al);

   void bic(Register dst, Register src1, const Operand& src2,
            SBit s = LeaveCC, Condition cond = al);
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.h     Thu May 27 00:31:10 2010
+++ /branches/bleeding_edge/src/arm/constants-arm.h     Tue Jun 22 01:38:32 2010
@@ -284,6 +284,9 @@
     // with immediate
   inline int RotateField() const { return Bits(11, 8); }
   inline int Immed8Field() const { return Bits(7, 0); }
+  inline int Immed4Field() const { return Bits(19, 16); }
+  inline int ImmedMovwMovtField() const {
+      return Immed4Field() << 12 | Offset12Field(); }

   // Fields used in Load/Store instructions
   inline int PUField() const { return Bits(24, 23); }
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc       Thu May 27 06:46:18 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc       Tue Jun 22 01:38:32 2010
@@ -101,6 +101,7 @@
   void PrintSRegister(int reg);
   void PrintDRegister(int reg);
   int FormatVFPRegister(Instr* instr, const char* format);
+  void PrintMovwMovt(Instr* instr);
   int FormatVFPinstruction(Instr* instr, const char* format);
   void PrintCondition(Instr* instr);
   void PrintShiftRm(Instr* instr);
@@ -373,6 +374,16 @@
     Print(format);
     return 0;
 }
+
+
+// Print the movw or movt instruction.
+void Decoder::PrintMovwMovt(Instr* instr) {
+  int imm = instr->ImmedMovwMovtField();
+  int rd = instr->RdField();
+  PrintRegister(rd);
+  out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                       ", #%d", imm);
+}


 // FormatOption takes a formatting string and interprets it based on
@@ -430,7 +441,12 @@
       return 1;
     }
     case 'm': {
-      if (format[1] == 'e') {  // 'memop: load/store instructions
+      if (format[1] == 'w') {
+        // 'mw: movt/movw instructions.
+        PrintMovwMovt(instr);
+        return 2;
+      }
+      if (format[1] == 'e') {  // 'memop: load/store instructions.
         ASSERT(STRING_STARTS_WITH(format, "memop"));
         if (instr->HasL()) {
           Print("ldr");
@@ -776,7 +792,7 @@
         if (instr->HasS()) {
           Format(instr, "tst'cond 'rn, 'shift_op");
         } else {
-          Unknown(instr);  // not used by V8
+          Format(instr, "movw'cond 'mw");
         }
         break;
       }
@@ -794,7 +810,7 @@
         if (instr->HasS()) {
           Format(instr, "cmp'cond 'rn, 'shift_op");
         } else {
-          Unknown(instr);  // not used by V8
+          Format(instr, "movt'cond 'mw");
         }
         break;
       }
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu May 27 06:46:18 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Jun 22 01:38:32 2010
@@ -1859,7 +1859,9 @@
           SetNZFlags(alu_out);
           SetCFlag(shifter_carry_out);
         } else {
-          UNIMPLEMENTED();
+          // Format(instr, "movw'cond 'rd, 'imm").
+          alu_out = instr->ImmedMovwMovtField();
+          set_register(rd, alu_out);
         }
         break;
       }
@@ -1888,7 +1890,10 @@
           SetCFlag(!BorrowFrom(rn_val, shifter_operand));
           SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
         } else {
-          UNIMPLEMENTED();
+          // Format(instr, "movt'cond 'rd, 'imm").
+          alu_out = (get_register(rd) & 0xffff) |
+              (instr->ImmedMovwMovtField() << 16);
+          set_register(rd, alu_out);
         }
         break;
       }
=======================================
--- /branches/bleeding_edge/src/jsregexp.cc     Mon Apr 26 08:10:42 2010
+++ /branches/bleeding_edge/src/jsregexp.cc     Tue Jun 22 01:38:32 2010
@@ -1747,9 +1747,11 @@
     if ((mask & char_mask) == char_mask) need_mask = false;
     mask &= char_mask;
   } else {
- // For 2-character preloads in ASCII mode we also use a 16 bit load with
-    // zero extend.
+    // For 2-character preloads in ASCII mode or 1-character preloads in
+    // TWO_BYTE mode we also use a 16 bit load with zero extend.
     if (details->characters() == 2 && compiler->ascii()) {
+      if ((mask & 0x7f7f) == 0x7f7f) need_mask = false;
+    } else if (details->characters() == 1 && !compiler->ascii()) {
       if ((mask & 0xffff) == 0xffff) need_mask = false;
     } else {
       if (mask == 0xffffffff) need_mask = false;
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Mon Jun 14 04:20:36 2010 +++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Tue Jun 22 01:38:32 2010
@@ -269,6 +269,33 @@
   COMPARE(mvn(r6, Operand(-1), LeaveCC, ne),
           "13a06000       movne r6, #0");

+  // mov -> movw.
+  if (CpuFeatures::IsSupported(ARMv7)) {
+    COMPARE(mov(r5, Operand(0x01234), LeaveCC, ne),
+            "13015234       movwne r5, #4660");
+ // We only disassemble one instruction so the eor instruction is not here.
+    COMPARE(eor(r5, r4, Operand(0x1234), LeaveCC, ne),
+            "1301c234       movwne ip, #4660");
+ // Movw can't do setcc so we don't get that here. Mov immediate with setcc
+    // is pretty strange anyway.
+    COMPARE(mov(r5, Operand(0x01234), SetCC, ne),
+            "159fc000       ldrne ip, [pc, #+0]");
+ // We only disassemble one instruction so the eor instruction is not here.
+    // The eor does the setcc so we get a movw here.
+    COMPARE(eor(r5, r4, Operand(0x1234), SetCC, ne),
+            "1301c234       movwne ip, #4660");
+
+    COMPARE(movt(r5, 0x4321, ne),
+            "13445321       movtne r5, #17185");
+    COMPARE(movw(r5, 0xabcd, eq),
+            "030a5bcd       movweq r5, #43981");
+  }
+
+ // Eor doesn't have an eor-negative variant, but we can do an mvn followed by
+  // an eor to get the same effect.
+  COMPARE(eor(r5, r4, Operand(0xffffff34), SetCC, ne),
+          "13e0c0cb       mvnne ip, #203");
+
   // and <-> bic.
   COMPARE(and_(r3, r5, Operand(0xfc03ffff)),
           "e3c537ff       bic r3, r5, #66846720");

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to