Revision: 5106
Author: [email protected]
Date: Wed Jul 21 00:42:51 2010
Log: Landing for Rodolph Perfetta.
Add support for saturation instruction (ARMv6 or above).
The byte array clamping code has been updated accordingly.
Review URL: http://codereview.chromium.org/3036008/show
http://code.google.com/p/v8/source/detail?r=5106
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/ic-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.h
/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 Thu Jul 8 05:38:02
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Wed Jul 21 00:42:51
2010
@@ -1190,6 +1190,30 @@
emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
15*B8 | B4 | src.code());
}
+
+
+// Saturating instructions.
+
+// Unsigned saturate.
+void Assembler::usat(Register dst,
+ int satpos,
+ const Operand& src,
+ Condition cond) {
+ // v6 and above.
+ ASSERT(CpuFeatures::IsSupported(ARMv7));
+ ASSERT(!dst.is(pc) && !src.rm_.is(pc));
+ ASSERT((satpos >= 0) && (satpos <= 31));
+ ASSERT((src.shift_op_ == ASR) || (src.shift_op_ == LSL));
+ ASSERT(src.rs_.is(no_reg));
+
+ int sh = 0;
+ if (src.shift_op_ == ASR) {
+ sh = 1;
+ }
+
+ emit(cond | 0x6*B24 | 0xe*B20 | satpos*B16 | dst.code()*B12 |
+ src.shift_imm_*B7 | sh*B6 | 0x1*B4 | src.rm_.code());
+}
// Bitfield manipulation instructions.
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Thu Jul 8 05:38:02 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Wed Jul 21 00:42:51 2010
@@ -445,6 +445,8 @@
}
Register rm() const { return rm_; }
+ Register rs() const { return rs_; }
+ ShiftOp shift_op() const { return shift_op_; }
private:
Register rm_;
@@ -834,6 +836,25 @@
void clz(Register dst, Register src, Condition cond = al); // v5 and
above
+ // Saturating instructions. v6 and above.
+
+ // Unsigned saturate.
+ //
+ // Saturate an optionally shifted signed value to an unsigned range.
+ //
+ // usat dst, #satpos, src
+ // usat dst, #satpos, src, lsl #sh
+ // usat dst, #satpos, src, asr #sh
+ //
+ // Register dst will contain:
+ //
+ // 0, if s < 0
+ // (1 << satpos) - 1, if s > ((1 << satpos) - 1)
+ // s, otherwise
+ //
+ // where s is the contents of src after shifting (if used.)
+ void usat(Register dst, int satpos, const Operand& src, Condition cond =
al);
+
// Bitfield manipulation instructions. v7 and above.
void ubfx(Register dst, Register src, int lsb, int width,
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc Thu Jul 8 05:38:02 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc Wed Jul 21 00:42:51 2010
@@ -106,6 +106,7 @@
void PrintCondition(Instr* instr);
void PrintShiftRm(Instr* instr);
void PrintShiftImm(Instr* instr);
+ void PrintShiftSat(Instr* instr);
void PrintPU(Instr* instr);
void PrintSoftwareInterrupt(SoftwareInterruptCodes swi);
@@ -246,6 +247,18 @@
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"#%d", imm);
}
+
+
+// Print the optional shift and immediate used by saturating instructions.
+void Decoder::PrintShiftSat(Instr* instr) {
+ int shift = instr->Bits(11, 7);
+ if (shift > 0) {
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ ", %s #%d",
+ shift_names[instr->Bit(6) * 2],
+ instr->Bits(11, 7));
+ }
+}
// Print PU formatting to reduce complexity of FormatOption.
@@ -440,6 +453,20 @@
}
return 1;
}
+ case 'i': { // 'i: immediate value from adjacent bits.
+ // Expects tokens in the form imm%...@%02d, ie. im...@07, im...@16
+ int width = (format[3] - '0') * 10 + (format[4] - '0');
+ int lsb = (format[6] - '0') * 10 + (format[7] - '0');
+
+ ASSERT((width >= 1) && (width <= 32));
+ ASSERT((lsb >= 0) && (lsb <= 31));
+ ASSERT((width + lsb) <= 32);
+
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "#%d",
+ instr->Bits(width + lsb - 1,
lsb));
+ return 8;
+ }
case 'l': { // 'l: branch and link
if (instr->HasLink()) {
Print("l");
@@ -507,7 +534,7 @@
return FormatRegister(instr, format);
}
case 's': {
- if (format[1] == 'h') { // 'shift_op or 'shift_rm
+ if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat.
if (format[6] == 'o') { // 'shift_op
ASSERT(STRING_STARTS_WITH(format, "shift_op"));
if (instr->TypeField() == 0) {
@@ -517,6 +544,10 @@
PrintShiftImm(instr);
}
return 8;
+ } else if (format[6] == 's') { // 'shift_sat.
+ ASSERT(STRING_STARTS_WITH(format, "shift_sat"));
+ PrintShiftSat(instr);
+ return 9;
} else { // 'shift_rm
ASSERT(STRING_STARTS_WITH(format, "shift_rm"));
PrintShiftRm(instr);
@@ -897,8 +928,16 @@
break;
}
case 1: {
- ASSERT(!instr->HasW());
- Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+ if (instr->HasW()) {
+ ASSERT(instr->Bits(5, 4) == 0x1);
+ if (instr->Bit(22) == 0x1) {
+ Format(instr, "usat 'rd, 'im...@16, 'rm'shift_sat");
+ } else {
+ UNREACHABLE(); // SSAT.
+ }
+ } else {
+ Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+ }
break;
}
case 2: {
=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc Tue Jul 20 23:59:34 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc Wed Jul 21 00:42:51 2010
@@ -1674,14 +1674,8 @@
__ cmp(r4, Operand(ip));
__ b(hs, &slow);
__ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
- { // Clamp the value to [0..255].
- Label done;
- __ tst(r5, Operand(0xFFFFFF00));
- __ b(eq, &done);
- __ mov(r5, Operand(0), LeaveCC, mi); // 0 if negative.
- __ mov(r5, Operand(255), LeaveCC, pl); // 255 if positive.
- __ bind(&done);
- }
+ __ Usat(r5, 8, Operand(r5)); // Clamp the value to [0..255].
+
// Get the pointer to the external array. This clobbers elements.
__ ldr(elements,
FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jul 12
06:23:42 2010
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Wed Jul 21
00:42:51 2010
@@ -279,6 +279,37 @@
bfc(dst, lsb, width, cond);
}
}
+
+
+void MacroAssembler::Usat(Register dst, int satpos, const Operand& src,
+ Condition cond) {
+ if (!CpuFeatures::IsSupported(ARMv7)) {
+ ASSERT(!dst.is(pc) && !src.rm().is(pc));
+ ASSERT((satpos >= 0) && (satpos <= 31));
+
+ // These asserts are required to ensure compatibility with the ARMv7
+ // implementation.
+ ASSERT((src.shift_op() == ASR) || (src.shift_op() == LSL));
+ ASSERT(src.rs().is(no_reg));
+
+ Label done;
+ int satval = (1 << satpos) - 1;
+
+ if (cond != al) {
+ b(NegateCondition(cond), &done); // Skip saturate if !condition.
+ }
+ if (!(src.is_reg() && dst.is(src.rm()))) {
+ mov(dst, src);
+ }
+ tst(dst, Operand(~satval));
+ b(eq, &done);
+ mov(dst, Operand(0), LeaveCC, mi); // 0 if negative.
+ mov(dst, Operand(satval), LeaveCC, pl); // satval if positive.
+ bind(&done);
+ } else {
+ usat(dst, satpos, src, cond);
+ }
+}
void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jul 12
06:23:42 2010
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Wed Jul 21
00:42:51 2010
@@ -112,6 +112,8 @@
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 Usat(Register dst, int satpos, const Operand& src,
+ Condition cond = al);
void Call(Label* target);
void Move(Register dst, Handle<Object> value);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jul 8 05:38:02
2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Jul 21 00:42:51
2010
@@ -2047,11 +2047,41 @@
case 0: {
ASSERT(!instr->HasW());
Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
+ UNIMPLEMENTED();
break;
}
case 1: {
- ASSERT(!instr->HasW());
- Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+ if (instr->HasW()) {
+ ASSERT(instr->Bits(5, 4) == 0x1);
+
+ if (instr->Bit(22) == 0x1) { // USAT.
+ int32_t sat_pos = instr->Bits(20, 16);
+ int32_t sat_val = (1 << sat_pos) - 1;
+ int32_t shift = instr->Bits(11, 7);
+ int32_t shift_type = instr->Bit(6);
+ int32_t rm_val = get_register(instr->RmField());
+ if (shift_type == 0) { // LSL
+ rm_val <<= shift;
+ } else { // ASR
+ rm_val >>= shift;
+ }
+ // If saturation occurs, the Q flag should be set in the CPSR.
+ // There is no Q flag yet, and no instruction (MRS) to read the
+ // CPSR directly.
+ if (rm_val > sat_val) {
+ rm_val = sat_val;
+ } else if (rm_val < 0) {
+ rm_val = 0;
+ }
+ set_register(rd, rm_val);
+ } else { // SSAT.
+ UNIMPLEMENTED();
+ }
+ return;
+ } else {
+ Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
+ UNIMPLEMENTED();
+ }
break;
}
case 2: {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h Fri May 7 13:02:57 2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.h Wed Jul 21 00:42:51 2010
@@ -294,6 +294,9 @@
void TrashCallerSaveRegisters();
// Architecture state.
+ // Saturating instructions require a Q flag to indicate saturation.
+ // There is currently no way to read the CPSR directly, and thus read
the Q
+ // flag, so this is left unimplemented.
int32_t registers_[16];
bool n_flag_;
bool z_flag_;
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Tue Jul 13
06:06:33 2010
+++ /branches/bleeding_edge/test/cctest/test-assembler-arm.cc Wed Jul 21
00:42:51 2010
@@ -309,5 +309,39 @@
CHECK_EQ(-7, res);
}
}
+
+
+TEST(6) {
+ // Test saturating instructions.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ Assembler assm(NULL, 0);
+
+ if (CpuFeatures::IsSupported(ARMv7)) {
+ CpuFeatures::Scope scope(ARMv7);
+ __ usat(r1, 8, Operand(r0)); // Sat 0xFFFF to 0-255 = 0xFF.
+ __ usat(r2, 12, Operand(r0, ASR, 9)); // Sat (0xFFFF>>9) to 0-4095 =
0x7F.
+ __ usat(r3, 1, Operand(r0, LSL, 16)); // Sat (0xFFFF<<16) to 0-1 =
0x0.
+ __ add(r0, r1, Operand(r2));
+ __ add(r0, r0, Operand(r3));
+ __ mov(pc, Operand(lr));
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = Heap::CreateCode(desc,
+ 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, 0xFFFF, 0, 0, 0, 0));
+ ::printf("f() = %d\n", res);
+ CHECK_EQ(382, res);
+ }
+}
#undef __
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu Jul 8
05:38:02 2010
+++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Wed Jul 21
00:42:51 2010
@@ -396,6 +396,15 @@
"e7df0f91 bfi r0, r1, #31, #1");
COMPARE(bfi(r1, r0, 31, 1),
"e7df1f90 bfi r1, r0, #31, #1");
+
+ COMPARE(usat(r0, 1, Operand(r1)),
+ "e6e10011 usat r0, #1, r1");
+ COMPARE(usat(r2, 7, Operand(lr)),
+ "e6e7201e usat r2, #7, lr");
+ COMPARE(usat(r3, 31, Operand(r4, LSL, 31)),
+ "e6ff3f94 usat r3, #31, r4, lsl #31");
+ COMPARE(usat(r8, 0, Operand(r5, ASR, 17)),
+ "e6e088d5 usat r8, #0, r5, asr #17");
}
VERIFY_RUN();
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev