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