Revision: 4744
Author: [email protected]
Date: Thu May 27 06:46:18 2010
Log: Update and improve support for ARMv7 bitfield instructions.
This is a commit of http://codereview.chromium.org/2124022
for Rodolph Perfetta.  I changed the test in
test-assembler-arm.cc so it only runs if ARMv7 is supported.

http://code.google.com/p/v8/source/detail?r=4744

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

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Wed May 26 04:19:39 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Thu May 27 06:46:18 2010
@@ -903,20 +903,6 @@

 // Data-processing instructions.

-// UBFX <Rd>,<Rn>,#<lsb>,#<width - 1>
-// Instruction details available in ARM DDI 0406A, A8-464.
-// cond(31-28) | 01111(27-23)| 1(22) | 1(21) | widthm1(20-16) |
-//  Rd(15-12) | lsb(11-7) | 101(6-4) | Rn(3-0)
-void Assembler::ubfx(Register dst, Register src1, const Operand& src2,
-                     const Operand& src3, Condition cond) {
-  ASSERT(!src2.rm_.is_valid() && !src3.rm_.is_valid());
-  ASSERT(static_cast<uint32_t>(src2.imm32_) <= 0x1f);
-  ASSERT(static_cast<uint32_t>(src3.imm32_) <= 0x1f);
-  emit(cond | 0x3F*B21 | src3.imm32_*B16 |
-       dst.code()*B12 | src2.imm32_*B7 | 0x5*B4 | src1.code());
-}
-
-
 void Assembler::and_(Register dst, Register src1, const Operand& src2,
                      SBit s, Condition cond) {
   addrmod1(cond | 0*B21 | s, src1, dst, src2);
@@ -1104,6 +1090,82 @@
   emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
        15*B8 | B4 | src.code());
 }
+
+
+// Bitfield manipulation instructions.
+
+// Unsigned bit field extract.
+// Extracts #width adjacent bits from position #lsb in a register, and
+// writes them to the low bits of a destination register.
+//   ubfx dst, src, #lsb, #width
+void Assembler::ubfx(Register dst,
+                     Register src,
+                     int lsb,
+                     int width,
+                     Condition cond) {
+  // v7 and above.
+  ASSERT(CpuFeatures::IsSupported(ARMv7));
+  ASSERT(!dst.is(pc) && !src.is(pc));
+  ASSERT((lsb >= 0) && (lsb <= 31));
+  ASSERT((width >= 1) && (width <= (32 - lsb)));
+  emit(cond | 0xf*B23 | B22 | B21 | (width - 1)*B16 | dst.code()*B12 |
+       lsb*B7 | B6 | B4 | src.code());
+}
+
+
+// Signed bit field extract.
+// Extracts #width adjacent bits from position #lsb in a register, and
+// writes them to the low bits of a destination register. The extracted
+// value is sign extended to fill the destination register.
+//   sbfx dst, src, #lsb, #width
+void Assembler::sbfx(Register dst,
+                     Register src,
+                     int lsb,
+                     int width,
+                     Condition cond) {
+  // v7 and above.
+  ASSERT(CpuFeatures::IsSupported(ARMv7));
+  ASSERT(!dst.is(pc) && !src.is(pc));
+  ASSERT((lsb >= 0) && (lsb <= 31));
+  ASSERT((width >= 1) && (width <= (32 - lsb)));
+  emit(cond | 0xf*B23 | B21 | (width - 1)*B16 | dst.code()*B12 |
+       lsb*B7 | B6 | B4 | src.code());
+}
+
+
+// Bit field clear.
+// Sets #width adjacent bits at position #lsb in the destination register
+// to zero, preserving the value of the other bits.
+//   bfc dst, #lsb, #width
+void Assembler::bfc(Register dst, int lsb, int width, Condition cond) {
+  // v7 and above.
+  ASSERT(CpuFeatures::IsSupported(ARMv7));
+  ASSERT(!dst.is(pc));
+  ASSERT((lsb >= 0) && (lsb <= 31));
+  ASSERT((width >= 1) && (width <= (32 - lsb)));
+  int msb = lsb + width - 1;
+  emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 | 0xf);
+}
+
+
+// Bit field insert.
+// Inserts #width adjacent bits from the low bits of the source register
+// into position #lsb of the destination register.
+//   bfi dst, src, #lsb, #width
+void Assembler::bfi(Register dst,
+                    Register src,
+                    int lsb,
+                    int width,
+                    Condition cond) {
+  // v7 and above.
+  ASSERT(CpuFeatures::IsSupported(ARMv7));
+  ASSERT(!dst.is(pc) && !src.is(pc));
+  ASSERT((lsb >= 0) && (lsb <= 31));
+  ASSERT((width >= 1) && (width <= (32 - lsb)));
+  int msb = lsb + width - 1;
+  emit(cond | 0x1f*B22 | msb*B16 | dst.code()*B12 | lsb*B7 | B4 |
+       src.code());
+}


 // Status register access instructions.
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Wed May 26 02:43:54 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Thu May 27 06:46:18 2010
@@ -671,8 +671,6 @@
   void blx(Label* L)  { blx(branch_offset(L, false)); }  // v5 and above

   // Data-processing instructions
-  void ubfx(Register dst, Register src1, const Operand& src2,
-            const Operand& src3, Condition cond = al);

   void and_(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
@@ -759,6 +757,19 @@

void clz(Register dst, Register src, Condition cond = al); // v5 and above

+  // Bitfield manipulation instructions. v7 and above.
+
+  void ubfx(Register dst, Register src, int lsb, int width,
+            Condition cond = al);
+
+  void sbfx(Register dst, Register src, int lsb, int width,
+            Condition cond = al);
+
+  void bfc(Register dst, int lsb, int width, Condition cond = al);
+
+  void bfi(Register dst, Register src, int lsb, int width,
+           Condition cond = al);
+
   // Status register access instructions

   void mrs(Register dst, SRegister s, Condition cond = al);
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc       Mon May 17 08:41:35 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc       Thu May 27 06:46:18 2010
@@ -401,6 +401,20 @@
       PrintCondition(instr);
       return 4;
     }
+    case 'f': {  // 'f: bitfield instructions - v7 and above.
+      uint32_t lsbit = instr->Bits(11, 7);
+      uint32_t width = instr->Bits(20, 16) + 1;
+      if (instr->Bit(21) == 0) {
+        // BFC/BFI:
+        // Bits 20-16 represent most-significant bit. Covert to width.
+        width -= lsbit;
+        ASSERT(width > 0);
+      }
+      ASSERT((width + lsbit) <= 32);
+      out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+                                           "#%d, #%d", lsbit, width);
+      return 1;
+    }
     case 'h': {  // 'h: halfword operation for extra loads and stores
       if (instr->HasH()) {
         Print("h");
@@ -446,16 +460,6 @@
         out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
                                              "%d", instr->Offset12Field());
         return 5;
-      } else if ((format[3] == '1') && (format[4] == '6')) {
-        ASSERT(STRING_STARTS_WITH(format, "off16to20"));
-        out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
-                                           "%d", instr->Bits(20, 16) +1);
-        return 9;
-      } else if (format[3] == '7') {
-        ASSERT(STRING_STARTS_WITH(format, "off7to11"));
-        out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
- "%d", instr->ShiftAmountField());
-        return 8;
       } else if (format[3] == '0') {
         // 'off0to3and8to19 16-bit immediate encoded in bits 19-8 and 3-0.
         ASSERT(STRING_STARTS_WITH(format, "off0to3and8to19"));
@@ -882,10 +886,26 @@
     case 3: {
       if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
         uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
-        uint32_t lsbit = static_cast<uint32_t>(instr->ShiftAmountField());
+        uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
         uint32_t msbit = widthminus1 + lsbit;
         if (msbit <= 31) {
-          Format(instr, "ubfx'cond 'rd, 'rm, #'off7to11, #'off16to20");
+          if (instr->Bit(22)) {
+            Format(instr, "ubfx'cond 'rd, 'rm, 'f");
+          } else {
+            Format(instr, "sbfx'cond 'rd, 'rm, 'f");
+          }
+        } else {
+          UNREACHABLE();
+        }
+      } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
+        uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
+        uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
+        if (msbit >= lsbit) {
+          if (instr->RmField() == 15) {
+            Format(instr, "bfc'cond 'rd, 'f");
+          } else {
+            Format(instr, "bfi'cond 'rd, 'rm, 'f");
+          }
         } else {
           UNREACHABLE();
         }
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu May 27 05:30:45 2010 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu May 27 06:46:18 2010
@@ -1287,7 +1287,7 @@
                                          Register src,
                                          int num_least_bits) {
   if (CpuFeatures::IsSupported(ARMv7)) {
-    ubfx(dst, src, Operand(kSmiTagSize), Operand(num_least_bits - 1));
+    ubfx(dst, src, kSmiTagSize, num_least_bits);
   } else {
     mov(dst, Operand(src, ASR, kSmiTagSize));
     and_(dst, dst, Operand((1 << num_least_bits) - 1));
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Mon May 17 08:41:35 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu May 27 06:46:18 2010
@@ -2031,7 +2031,6 @@


 void Simulator::DecodeType3(Instr* instr) {
-  ASSERT(instr->Bits(6, 4) == 0x5 || instr->Bit(4) == 0);
   int rd = instr->RdField();
   int rn = instr->RnField();
   int32_t rn_val = get_register(rn);
@@ -2058,17 +2057,47 @@
       break;
     }
     case 3: {
-      // UBFX.
       if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
         uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
-        uint32_t lsbit = static_cast<uint32_t>(instr->ShiftAmountField());
+        uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
         uint32_t msbit = widthminus1 + lsbit;
         if (msbit <= 31) {
-          uint32_t rm_val =
-              static_cast<uint32_t>(get_register(instr->RmField()));
-          uint32_t extr_val = rm_val << (31 - msbit);
-          extr_val = extr_val >> (31 - widthminus1);
-          set_register(instr->RdField(), extr_val);
+          if (instr->Bit(22)) {
+            // ubfx - unsigned bitfield extract.
+            uint32_t rm_val =
+                static_cast<uint32_t>(get_register(instr->RmField()));
+            uint32_t extr_val = rm_val << (31 - msbit);
+            extr_val = extr_val >> (31 - widthminus1);
+            set_register(instr->RdField(), extr_val);
+          } else {
+            // sbfx - signed bitfield extract.
+            int32_t rm_val = get_register(instr->RmField());
+            int32_t extr_val = rm_val << (31 - msbit);
+            extr_val = extr_val >> (31 - widthminus1);
+            set_register(instr->RdField(), extr_val);
+          }
+        } else {
+          UNREACHABLE();
+        }
+        return;
+      } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
+        uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
+        uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
+        if (msbit >= lsbit) {
+          // bfc or bfi - bitfield clear/insert.
+          uint32_t rd_val =
+              static_cast<uint32_t>(get_register(instr->RdField()));
+          uint32_t bitcount = msbit - lsbit + 1;
+          uint32_t mask = (1 << bitcount) - 1;
+          rd_val &= ~(mask << lsbit);
+          if (instr->RmField() != 15) {
+            // bfi - bitfield insert.
+            uint32_t rm_val =
+                static_cast<uint32_t>(get_register(instr->RmField()));
+            rm_val &= mask;
+            rd_val |= rm_val << lsbit;
+          }
+          set_register(instr->RdField(), rd_val);
         } else {
           UNREACHABLE();
         }
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Mar 23 04:40:38 2010 +++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Thu May 27 06:46:18 2010
@@ -279,5 +279,41 @@
     CHECK_EQ(1.5, t.a);
   }
 }
+
+
+TEST(5) {
+  // Test the ARMv7 bitfield instructions.
+  InitializeVM();
+  v8::HandleScope scope;
+
+  Assembler assm(NULL, 0);
+
+  if (CpuFeatures::IsSupported(ARMv7)) {
+    CpuFeatures::Scope scope(ARMv7);
+    // On entry, r0 = 0xAAAAAAAA = 0b10..10101010.
+    __ ubfx(r0, r0, 1, 12);  // 0b00..010101010101 = 0x555
+    __ sbfx(r0, r0, 0, 5);   // 0b11..111111110101 = -11
+    __ bfc(r0, 1, 3);        // 0b11..111111110001 = -15
+    __ mov(r1, Operand(7));
+    __ bfi(r0, r1, 3, 3);    // 0b11..111111111001 = -7
+    __ mov(pc, Operand(lr));
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Object* code = Heap::CreateCode(desc,
+                                    NULL,
+                                    Code::ComputeFlags(Code::STUB),
+ Handle<Object>(Heap::undefined_value()));
+    CHECK(code->IsCode());
+#ifdef DEBUG
+    Code::cast(code)->Print();
+#endif
+    F1 f = FUNCTION_CAST<F1>(Code::cast(code)->entry());
+    int res = reinterpret_cast<int>(
+                CALL_GENERATED_CODE(f, 0xAAAAAAAA, 0, 0, 0, 0));
+    ::printf("f() = %d\n", res);
+    CHECK_EQ(-7, res);
+  }
+}

 #undef __
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu Apr 8 06:30:48 2010 +++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu May 27 06:46:18 2010
@@ -289,3 +289,49 @@

   VERIFY_RUN();
 }
+
+
+TEST(Type3) {
+  SETUP();
+
+  if (CpuFeatures::IsSupported(ARMv7)) {
+    COMPARE(ubfx(r0, r1, 5, 10),
+            "e7e902d1       ubfx r0, r1, #5, #10");
+    COMPARE(ubfx(r1, r0, 5, 10),
+            "e7e912d0       ubfx r1, r0, #5, #10");
+    COMPARE(ubfx(r0, r1, 31, 1),
+            "e7e00fd1       ubfx r0, r1, #31, #1");
+    COMPARE(ubfx(r1, r0, 31, 1),
+            "e7e01fd0       ubfx r1, r0, #31, #1");
+
+    COMPARE(sbfx(r0, r1, 5, 10),
+            "e7a902d1       sbfx r0, r1, #5, #10");
+    COMPARE(sbfx(r1, r0, 5, 10),
+            "e7a912d0       sbfx r1, r0, #5, #10");
+    COMPARE(sbfx(r0, r1, 31, 1),
+            "e7a00fd1       sbfx r0, r1, #31, #1");
+    COMPARE(sbfx(r1, r0, 31, 1),
+            "e7a01fd0       sbfx r1, r0, #31, #1");
+
+    COMPARE(bfc(r0, 5, 10),
+            "e7ce029f       bfc r0, #5, #10");
+    COMPARE(bfc(r1, 5, 10),
+            "e7ce129f       bfc r1, #5, #10");
+    COMPARE(bfc(r0, 31, 1),
+            "e7df0f9f       bfc r0, #31, #1");
+    COMPARE(bfc(r1, 31, 1),
+            "e7df1f9f       bfc r1, #31, #1");
+
+    COMPARE(bfi(r0, r1, 5, 10),
+            "e7ce0291       bfi r0, r1, #5, #10");
+    COMPARE(bfi(r1, r0, 5, 10),
+            "e7ce1290       bfi r1, r0, #5, #10");
+    COMPARE(bfi(r0, r1, 31, 1),
+            "e7df0f91       bfi r0, r1, #31, #1");
+    COMPARE(bfi(r1, r0, 31, 1),
+            "e7df1f90       bfi r1, r0, #31, #1");
+  }
+
+  VERIFY_RUN();
+}
+

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

Reply via email to